home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / x11 / xcloseup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  78.5 KB  |  3,112 lines  |  [TEXT/R*ch]

  1. /* Closeups for the X11 interface to Xconq.
  2.    Copyright (C) 1995, 1996 Massimo Campostrini and Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /*  1) unit closeup                        */
  10. /*  2) side closeup                        */
  11. /*  3) unit list                           */
  12. /*  4) list (summary) of unit closeups     */
  13.  
  14. #include "conq.h"
  15. #include "xconq.h"
  16. extern void create_orders_window PARAMS ((Side *side, Map *map));
  17.  
  18. static void buffer_append PARAMS ((int nl));
  19. static void add_to_closeup_summary
  20.     PARAMS ((UnitCloseup *unitcloseup, Side *side));
  21. static void remove_from_closeup_summary
  22.     PARAMS ((UnitCloseup *unitcloseup, Side *side));
  23. static void summary_list_callback 
  24.     PARAMS ((Widget w, XtPointer dummy, XawListReturnStruct *list));
  25. static void unit_closeup_update 
  26.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  27. static void unit_closeup_focus
  28.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  29. static void unit_closeup_close 
  30.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  31. static void side_closeup_update 
  32.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  33. static void side_closeup_close 
  34.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  35. static void side_closeup_close 
  36.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  37. static void side_closeup_type_callback 
  38.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  39. static void side_closeup_all_types_callback 
  40.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  41. static void build_unit_list
  42.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  43. static void unit_list_callback 
  44.     PARAMS ((Widget w, XtPointer dummy, XawListReturnStruct *list));
  45. static void unit_list_close
  46.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  47. static UnitList *find_unit_list_via_button PARAMS ((Widget w, Side *side));
  48. void destroy_unit_list PARAMS ((UnitList *unit_list, Side *side));
  49. char *pad_string PARAMS ((char *str, int n, int min));
  50. void one_line_unit_summary 
  51.     PARAMS ((char *buf, Unit *unit, Side *side, int pos));
  52. void hp_and_acp_desc PARAMS ((char *buf, Unit *unit, char *sep));
  53.  
  54. void list_unit_types PARAMS ((char *buff, int nums[])); 
  55. void RaiseWidget PARAMS ((Widget w));
  56.  
  57. Widget new_order_widgets 
  58.     PARAMS ((Side *side, OrderInterface *ordi, int num, Widget up));
  59. void sorder_cond_name 
  60.     PARAMS ((char *buffer, StandingOrder *sorder, Side *side));
  61. void update_order_widgets PARAMS 
  62.     ((Side *side, OrderInterface *ordi, 
  63.       StandingOrder *sorder, char *types, Task *task));
  64. static void orders_help_call
  65.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  66. static void orders_done_help_call
  67.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  68. static void handle_done_orders_help 
  69.     PARAMS ((Widget w, XEvent *event, String *params, Cardinal *num_params));
  70. static void handle_done_string_select 
  71.     PARAMS ((Widget w, XEvent *event, String *params, Cardinal *num_params));
  72. static void orders_add_call
  73.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  74. static void orders_delete_call
  75.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  76. static void orders_undo_call
  77.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  78. static void orders_quit_call
  79.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  80. static void order_toggle_call
  81.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  82. static void order_types_call
  83.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  84. static void order_etype_call
  85.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  86. static void order_eparms_call
  87.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  88. static void order_task_call
  89.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  90. static void order_tparms_call
  91.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  92. void set_cell_from_map PARAMS 
  93.     ((Side *side, Map *map, char *prompt, void *px, void *py, int size));
  94. static void aux_set_cell PARAMS ((Side *side, Map *map, int cancel));
  95. void set_unit_from_map PARAMS 
  96.     ((Side *side, Map *map, char *prompt, int *puid));
  97. static void aux_set_unit PARAMS ((Side *side, Map *map, int cancel));
  98. int find_side_and_ordi_via_widget
  99.     PARAMS ((Widget w, Side **sidep, OrderInterface **ordip));
  100. OrderInterface *active_ordi PARAMS ((Side *side));
  101. int utype_select_popup PARAMS ((Side *side, Position x, Position y));
  102. static void utype_select_call 
  103.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  104. int dir_select_popup PARAMS ((Side *side, Position x, Position y));
  105. static void dir_select_call 
  106.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  107. int integer_select_popup 
  108.     PARAMS ((Side *side, Position x, Position y, int init, char *prompt));
  109. void string_select_popup 
  110.     PARAMS ((Side *side, Position x, Position y,
  111.          char *result, char *init, char *prompt));
  112. int cond_select_popup PARAMS ((Side *side, Position x, Position y));
  113. static void cond_select_call 
  114.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  115. int task_select_popup PARAMS ((Side *side, Position x, Position y));
  116. static void task_select_call 
  117.     PARAMS ((Widget w, XtPointer client_data, XtPointer call_data));
  118. int count_sorder PARAMS ((Side *side));
  119. int num_tasks PARAMS ((void));
  120.  
  121. static char buffer[200], tmpbuf[50], *longbuffer = NULL;
  122. /* initial lengths of arrays, they will grow when needed */
  123. static int longbuffer_length = 1000, unitlist_size = 100, summary_size = 100;
  124.  
  125. #define OTHERFILTERS 4  /* filters not based on unit typs */
  126. #define MAXFILTERS (MAXUTYPES+OTHERFILTERS+1)
  127. #define LISTLINE 80
  128.  
  129. /* manage unit closeups */
  130.  
  131. UnitCloseup *
  132. find_unit_closeup(unit, side)
  133. Unit *unit;
  134. Side *side;
  135. {
  136.     UnitCloseup *unitcloseup;
  137.     
  138.     for_all_unit_closeups(unitcloseup,side) {
  139.     if (unitcloseup->unit == unit
  140.         && unitcloseup->shell)
  141.       return unitcloseup;
  142.     }
  143.     return NULL;
  144. }
  145.  
  146. UnitCloseup *
  147. find_unit_closeup_via_button(w, side)
  148. Widget w;
  149. Side *side;
  150. {
  151.     UnitCloseup *unitcloseup;
  152.     Widget shell = XtParent(XtParent(w));
  153.  
  154.     for_all_unit_closeups(unitcloseup,side) {
  155.     if (unitcloseup->shell == shell)
  156.       return unitcloseup;
  157.     }
  158.     return NULL;
  159. }
  160.  
  161. UnitCloseup *
  162. create_unit_closeup(unit, side, map)
  163. Unit *unit;
  164. Side *side;
  165. Map *map;
  166. {
  167.     Widget cmd, up, left, form;
  168.     UnitCloseup *unitcloseup = (UnitCloseup *) xmalloc(sizeof(UnitCloseup));
  169.     Side *side1;
  170.  
  171.     if (!active_display(side) || unit == NULL)
  172.       return NULL;
  173.  
  174.     side1 = unit->side;
  175.     if (side1 == NULL)
  176.       side1 = indepside;
  177.  
  178.     unitcloseup->unit = unit;
  179.     unitcloseup->map = map;
  180.  
  181.     /* create the popup */
  182.     strcpy(buffer, "xconq closeup: ");
  183.     strcat(buffer, unit_handle(side, unit));
  184.     strcpy(spbuf, "xconq: ");
  185.     strcat(spbuf, short_unit_handle(unit));
  186.     unitcloseup->shell =
  187.       XtVaCreatePopupShell("unitCloseup", topLevelShellWidgetClass,
  188.                side->ui->shell,
  189.                XtNtitle, buffer,
  190.                XtNiconName, spbuf,
  191.                NULL);
  192.  
  193.     form =
  194.       XtVaCreateManagedWidget("form", formWidgetClass, unitcloseup->shell,
  195.                   NULL);
  196.     left = up = 
  197.       XtVaCreateManagedWidget("icon", labelWidgetClass, form,
  198.                   XtNbitmap, get_unit_picture(unit->type, side),
  199.                   XtNtop,    XawChainTop, 
  200.                   XtNbottom, XawChainTop, 
  201.                   XtNleft,   XawChainLeft, 
  202.                   XtNright,  XawChainLeft,
  203.                   NULL);
  204.     left =
  205.       XtVaCreateManagedWidget("label", labelWidgetClass, form,
  206.                   XtNfromHoriz, left,
  207.                   XtNlabel,  unit_handle(side, unit),
  208.                   XtNtop,    XawChainTop, 
  209.                   XtNbottom, XawChainTop, 
  210.                   XtNleft,   XawChainLeft, 
  211.                   XtNright,  XawChainLeft,
  212.                   NULL);
  213.  
  214.     left =
  215.       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
  216.                   XtNbitmap, get_side_picture(side, side1),
  217.                   XtNlabel, "",
  218.                   XtNfromHoriz, left,
  219.                   XtNtop,    XawChainTop, 
  220.                   XtNbottom, XawChainTop, 
  221.                   XtNleft,   XawChainLeft, 
  222.                   XtNright,  XawChainLeft,
  223.                   NULL);
  224.  
  225.     left =
  226.       XtVaCreateManagedWidget("side", labelWidgetClass, form,
  227.                   XtNfromHoriz, left,
  228.                   XtNlabel,  side_adjective(side1),
  229.                   XtNtop,    XawChainTop, 
  230.                   XtNbottom, XawChainTop, 
  231.                   XtNleft,   XawChainLeft, 
  232.                   XtNright,  XawChainLeft,
  233.                   NULL);
  234.  
  235.     up = unitcloseup->info =
  236.       XtVaCreateManagedWidget("info", asciiTextWidgetClass, form,
  237.                   XtNfromVert, up,
  238.                   XtNdisplayCaret, False,
  239.                   XtNeditType, XawtextRead,
  240.                   XtNscrollHorizontal, XawtextScrollWhenNeeded, 
  241.                   XtNscrollVertical, XawtextScrollWhenNeeded,
  242.                   XtNtop,    XawChainTop, 
  243.                   XtNbottom, XawChainBottom, 
  244.                   XtNleft,   XawChainLeft, 
  245.                   XtNright,  XawChainRight, 
  246.                   NULL);
  247.  
  248.     left = cmd =
  249.       XtVaCreateManagedWidget("update", commandWidgetClass, form,
  250.                   XtNfromVert,  up,
  251.                   XtNtop,    XawChainBottom, 
  252.                   XtNbottom, XawChainBottom, 
  253.                   XtNleft,   XawChainLeft, 
  254.                   XtNright,  XawChainLeft, 
  255.                   NULL);
  256.     XtAddCallback(cmd, XtNcallback, unit_closeup_update, NULL);
  257.     left = cmd =
  258.       XtVaCreateManagedWidget("focus", commandWidgetClass, form,
  259.                   XtNfromHoriz, left,
  260.                   XtNfromVert,  up,
  261.                   XtNtop,    XawChainBottom, 
  262.                   XtNbottom, XawChainBottom, 
  263.                   XtNleft,   XawChainLeft, 
  264.                   XtNright,  XawChainLeft, 
  265.                   NULL);
  266.     XtAddCallback(cmd, XtNcallback, unit_closeup_focus, NULL);
  267.  
  268.     cmd =
  269.       XtVaCreateManagedWidget("close", commandWidgetClass, form,
  270.                   XtNfromHoriz, left,
  271.                   XtNfromVert,  up,
  272.                   XtNtop,    XawChainBottom, 
  273.                   XtNbottom, XawChainBottom, 
  274.                   XtNleft,   XawChainLeft, 
  275.                   XtNright,  XawChainLeft, 
  276.                   NULL);
  277.     XtAddCallback(cmd, XtNcallback, unit_closeup_close, NULL);
  278.  
  279.     /* insert in the side's unit closeup list */
  280.     unitcloseup->next = side->ui->unitcloseuplist;
  281.     side->ui->unitcloseuplist = unitcloseup;
  282.  
  283.     XtPopup(unitcloseup->shell, XtGrabNone);
  284.  
  285.     add_to_closeup_summary(unitcloseup, side);
  286.  
  287.     return unitcloseup;
  288. }
  289.  
  290. void
  291. destroy_unit_closeup(unitcloseup, side)
  292. UnitCloseup *unitcloseup;
  293. Side *side;
  294. {
  295.     UnitCloseup *uc;
  296.  
  297.     XtPopdown(unitcloseup->shell);
  298.     XtDestroyWidget(unitcloseup->shell);
  299.  
  300.     remove_from_closeup_summary(unitcloseup, side);
  301.  
  302.     /* remove from the side's unit closeup list */
  303.     if (side->ui->unitcloseuplist == unitcloseup) {
  304.     side->ui->unitcloseuplist = unitcloseup->next;
  305.     } else {
  306.     for_all_unit_closeups(uc,side) {
  307.         if (uc->next == unitcloseup) {
  308.         uc->next = unitcloseup->next;
  309.         }
  310.     }
  311.     }
  312.     free(unitcloseup);
  313. }
  314.  
  315. /* conveniency routine to append the contents of "buffer" */
  316. /* into "longbuffer", growing it if needed */
  317. /* append a newline if nl is not zero */
  318. static void 
  319. buffer_append(nl) 
  320. int nl;
  321. {
  322.     int len, longl;
  323.  
  324.     longl = strlen(longbuffer);
  325.     if (nl) 
  326.       strcat(buffer, "\n");
  327.     len = strlen(buffer);
  328.  
  329.     if (len+longl > longbuffer_length-2) {
  330.     longbuffer_length *= 2;
  331.     longbuffer = (char *) realloc(longbuffer,
  332.                       longbuffer_length*sizeof(char));
  333.     }
  334.     strcat(longbuffer, buffer);
  335.     buffer[0] = '\0';  /* clear buffer */
  336. }
  337.  
  338. void
  339. draw_unit_closeup(unitcloseup, side)
  340. UnitCloseup *unitcloseup;
  341. Side *side;
  342. {
  343.     int m, u, i;
  344.     Unit *unit = unitcloseup->unit, *occupant;
  345.     char *featurename;
  346.  
  347.     if (!active_display(side))
  348.       return;
  349.     if (!in_play(unit) ||
  350.     !(side_controls_unit(side, unit) || endofgame || side->designer)) {
  351.     /* If the unit is no longer alive and ours, shut down the window. */
  352.     destroy_unit_closeup(unitcloseup,side);
  353.     return;
  354.     }
  355.  
  356.     if (longbuffer==NULL) {
  357.     longbuffer = (char *) xmalloc(longbuffer_length*sizeof(char));
  358.     }
  359.     longbuffer[0] = '\0';
  360.  
  361.     /* Draw the unit's side and type. */
  362.     strcpy(buffer, unit_handle(side, unit));
  363.     pad_string(buffer, 40, 3);
  364.     buffer_append(0);
  365.  
  366.     /* Draw the unit's HP, CP and ACP */
  367.     hp_and_acp_desc(buffer, unit, "   ");
  368.     buffer_append(1);
  369.  
  370.     /* Draw the unit's location. */
  371.     if (unit->transport != NULL) {
  372.     sprintf(buffer, "In %s (", short_unit_handle(unit->transport));
  373.     }
  374.     if (terrain_visible(side, unit->x, unit->y)) {
  375.     sprintf(spbuf, "In %s", t_type_name(terrain_at(unit->x, unit->y)));
  376.     linear_desc(spbuf, unit->x, unit->y);
  377.     if (unit->transport != NULL) {
  378.         spbuf[0] = tolower(spbuf[0]);
  379.     }
  380.     strcat(buffer, spbuf);
  381.     if (unit->transport == NULL) {
  382.         featurename = feature_name_at(unit->x, unit->y);
  383.         if (!empty_string(featurename))
  384.           tprintf(buffer, " (%s)", featurename);
  385.         if (temperatures_defined())
  386.           tprintf(buffer, " (T %d)", temperature_at(unit->x, unit->y));
  387.         if (elevations_defined())
  388.           tprintf(buffer, " (El %d)", elev_at(unit->x, unit->y));
  389.         /* (should list local weather also) */
  390.     }
  391.     strcat(buffer," ");
  392.     }
  393.     tprintf(buffer, "at %d,%d", unit->x, unit->y);
  394.     if (unit->transport != NULL) {
  395.     strcat(buffer,")");
  396.     }
  397.     pad_string(buffer, 40, 3);
  398.     buffer_append(0);
  399.  
  400.     /* Draw the unit's supplies. */
  401.     i = 0;
  402.     for_all_material_types(m) {
  403.     if (um_storage_x(unit->type, m) > 0) {
  404.         sprintf(buffer, "%s%s %d/%d", i ? ", " : "",
  405.             m_type_name(m), unit->supply[m],
  406.             um_storage_x(unit->type, m));
  407.         i = 1;
  408.         buffer_append(0);
  409.     }
  410.     }
  411.     buffer_append(1);
  412.  
  413.     /* Draw the unit's toolup level (if any) */
  414.     if (unit->tooling != NULL) {
  415.     i = 0;
  416.     for_all_unit_types(u) {
  417.         i = i || unit->tooling[u];
  418.     }
  419.     if (i) {
  420.         buffer_append(1);
  421.         strcpy(buffer, "Toolup level: ");
  422.         for_all_unit_types(u) {
  423.         if (unit->tooling[u]) {
  424.             if (unit->tooling[u]<uu_tp_max(unit->type, u)) {
  425.             tprintf(buffer, "%d/%d%1s ",
  426.                 unit->tooling[u], uu_tp_max(unit->type, u),
  427.                 utype_name_n(u, 1));
  428.             } else {
  429.             tprintf(buffer, "%d%1s ", unit->tooling[u],
  430.                 utype_name_n(u, 1));
  431.             }
  432.         }
  433.         }
  434.         buffer_append(1);
  435.     }
  436.     }
  437.     
  438.     /* Draw the unit's plan, if it has one. */
  439.     if (unit->plan) {
  440.     Task *task;
  441.     Plan *plan = unit->plan;
  442.  
  443.     strcpy(buffer, "\nplan:  ");
  444.     buffer_append(0);
  445.  
  446.     plan_desc(buffer, unit);
  447.  
  448.         if (plan->maingoal) {
  449.         strcat(buffer, "   ");
  450.         /* (should use a "goal_desc" routine) */
  451.         strcat(buffer, goal_desig(plan->maingoal));
  452.         }
  453.         if (plan->formation) {
  454.         strcat(buffer, "   ");
  455.         /* (should use a "goal_desc" routine) */
  456.         strcat(buffer, goal_desig(plan->formation));
  457.         }
  458.     buffer_append(1);
  459.     if (plan->tasks) {
  460.         for (task = plan->tasks; task != NULL; task = task->next) {
  461.         task_desc(buffer, task);
  462.         buffer_append(1);
  463.         }
  464.     }
  465.     }
  466.  
  467.     /* Draw the unit's occupants */
  468.     if (unit->occupant != NULL) {
  469.     strcpy(buffer,"\n        Occupants:");
  470.     buffer_append(1);
  471.     for_all_occupants(unit,occupant) {
  472.         one_line_unit_summary(buffer, occupant, side, 0);
  473.         buffer_append(1);
  474.     }
  475.     }
  476.  
  477.     XtVaSetValues(unitcloseup->info, XtNstring, longbuffer, NULL);
  478.  
  479.     RaiseWidget(unitcloseup->shell);
  480. }
  481.  
  482. /* manage side closeups */
  483. /* "side" is the side owning the display */
  484. /* "side1" is the side shown in closeup */
  485.  
  486. SideCloseup *
  487. find_side_closeup(side1, side)
  488. Side *side1;
  489. Side *side;
  490. {
  491.     SideCloseup *sidecloseup;
  492.  
  493.     if (side1 == NULL)
  494.       side1 = indepside;
  495.     for_all_side_closeups(sidecloseup,side) {
  496.     if (sidecloseup->side == side1
  497.         && sidecloseup->shell)
  498.       return sidecloseup;
  499.     }
  500.     return NULL;
  501. }
  502.  
  503. SideCloseup *
  504. find_side_closeup_via_button(w, side)
  505. Widget w;
  506. Side *side;
  507. {
  508.     SideCloseup *sidecloseup;
  509.     Widget shell = XtParent(XtParent(w));
  510.  
  511.     for_all_side_closeups(sidecloseup,side) {
  512.     if (sidecloseup->shell == shell)
  513.       return sidecloseup;
  514.     }
  515.     return NULL;
  516. }
  517.  
  518. SideCloseup *
  519. create_side_closeup(side1, side, map)
  520. Side *side1;
  521. Side *side;
  522. Map *map;
  523. {
  524.     int u, fn;
  525.     Widget cmd, up, left, box, form, radio;
  526.     SideCloseup *sidecloseup = (SideCloseup *) xmalloc(sizeof(SideCloseup));
  527.     sidecloseup->filter =
  528.       (Widget *) xmalloc((numutypes+OTHERFILTERS+1)*sizeof(Widget));
  529.  
  530.     if (!active_display(side))
  531.       return NULL;
  532.     /* prevent crash when showing the independent side */
  533.     if (side1 == NULL)
  534.       side1 = indepside;
  535.  
  536.     sidecloseup->side = side1;
  537.     sidecloseup->map = map;
  538.  
  539.     /* create the popup */
  540.     strcpy(buffer, "xconq closeup: ");
  541.     strcat(buffer, short_side_title(side1));
  542.     strcpy(spbuf, "xconq: ");
  543.     strcat(spbuf, short_side_title(side1));
  544.     sidecloseup->shell =
  545.       XtVaCreatePopupShell("sideCloseup", topLevelShellWidgetClass,
  546.                side->ui->shell,
  547.                XtNtitle, buffer,
  548.                XtNiconName, spbuf,
  549.                NULL);
  550.  
  551.     form =
  552.       XtVaCreateManagedWidget("form", formWidgetClass, sidecloseup->shell,
  553.                   NULL);
  554.     left = up =
  555.       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
  556.                   XtNbitmap, get_side_picture(side, side1),
  557.                   XtNlabel, "",
  558.                   XtNtop,    XawChainTop, 
  559.                   XtNbottom, XawChainTop, 
  560.                   XtNleft,   XawChainLeft, 
  561.                   XtNright,  XawChainLeft,
  562.                   NULL);
  563.  
  564.     left =
  565.       XtVaCreateManagedWidget("side", labelWidgetClass, form,
  566.                   XtNfromHoriz, left,
  567.                   XtNlabel,  short_side_title(side1),
  568.                   XtNtop,    XawChainTop, 
  569.                   XtNbottom, XawChainTop, 
  570.                   XtNleft,   XawChainLeft, 
  571.                   XtNright,  XawChainLeft,
  572.                   NULL);
  573.  
  574.     up = sidecloseup->info =
  575.       XtVaCreateManagedWidget("info", asciiTextWidgetClass, form,
  576.                   XtNfromVert, up,
  577.                   XtNdisplayCaret, False,
  578.                   XtNeditType, XawtextRead,
  579.                   XtNscrollHorizontal, XawtextScrollWhenNeeded, 
  580.                   XtNscrollVertical, XawtextScrollWhenNeeded,
  581.                   XtNtop,    XawChainTop, 
  582.                   XtNbottom, XawChainBottom, 
  583.                   XtNleft,   XawChainLeft, 
  584.                   XtNright,  XawChainRight, 
  585.                   NULL);
  586.  
  587.     up = box =
  588.       XtVaCreateManagedWidget("filter", boxWidgetClass, form,
  589.                   XtNfromVert,  up,
  590.                   XtNtop,    XawChainBottom, 
  591.                   XtNbottom, XawChainBottom, 
  592.                   XtNleft,   XawChainLeft, 
  593.                   XtNright,  XawChainLeft, 
  594.                   NULL);
  595.     XtVaCreateManagedWidget("label", labelWidgetClass, box,
  596.                 NULL);
  597.  
  598.     fn = 0;
  599.     /* unit type filters; managed by their callbacks */
  600.     sidecloseup->filter[fn] =
  601.       XtVaCreateManagedWidget("allTypes", toggleWidgetClass, box,
  602.                   XtNstate, True,
  603.                   NULL);
  604.     XtAddCallback(sidecloseup->filter[fn++], XtNcallback,
  605.           side_closeup_all_types_callback, NULL);
  606.  
  607.     for_all_unit_types(u) {
  608.     sidecloseup->filter[fn] =
  609.       XtVaCreateManagedWidget(utype_name_n(u,8), toggleWidgetClass, box,
  610.                   XtNbitmap, get_unit_picture(u, side),
  611.                   XtNstate, False,
  612.                   NULL);
  613.     XtAddCallback(sidecloseup->filter[fn++], XtNcallback,
  614.           side_closeup_type_callback, NULL);
  615.     }
  616.     /* other filters; managed as a radio group (at most one is set) */
  617.     radio = sidecloseup->filter[fn] =
  618.       XtVaCreateManagedWidget("completed", toggleWidgetClass, box,
  619.                   XtNstate, True,
  620.                 NULL);
  621.     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
  622.     sidecloseup->filter[fn] =
  623.       XtVaCreateManagedWidget("waiting", toggleWidgetClass, box,
  624.                   XtNstate, False,
  625.                   NULL);
  626.     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
  627.     sidecloseup->filter[fn] =
  628.       XtVaCreateManagedWidget("acpLeft", toggleWidgetClass, box,
  629.                   XtNstate, False,
  630.                   NULL);
  631.     XawToggleChangeRadioGroup(sidecloseup->filter[fn++], radio);
  632.  
  633.     left = cmd =
  634.       XtVaCreateManagedWidget("update", commandWidgetClass, form,
  635.                   XtNfromVert,  up,
  636.                   XtNtop,    XawChainBottom, 
  637.                   XtNbottom, XawChainBottom, 
  638.                   XtNleft,   XawChainLeft, 
  639.                   XtNright,  XawChainLeft, 
  640.                   NULL);
  641.     XtAddCallback(cmd, XtNcallback, side_closeup_update, NULL);
  642.  
  643.     left = cmd =
  644.       XtVaCreateManagedWidget("listUnits", commandWidgetClass, form,
  645.                   XtNfromHoriz, left,
  646.                   XtNfromVert,  up,
  647.                   XtNtop,    XawChainBottom, 
  648.                   XtNbottom, XawChainBottom, 
  649.                   XtNleft,   XawChainLeft, 
  650.                   XtNright,  XawChainLeft, 
  651.                   NULL);
  652.     XtAddCallback(cmd, XtNcallback, build_unit_list, NULL);
  653.  
  654.     cmd =
  655.       XtVaCreateManagedWidget("close", commandWidgetClass, form,
  656.                   XtNfromHoriz, left,
  657.                   XtNfromVert,  up,
  658.                   XtNtop,    XawChainBottom, 
  659.                   XtNbottom, XawChainBottom, 
  660.                   XtNleft,   XawChainLeft, 
  661.                   XtNright,  XawChainLeft, 
  662.                   NULL);
  663.     XtAddCallback(cmd, XtNcallback, side_closeup_close, NULL);
  664.  
  665.     sprintf(spbuf, "Closeup on %s", short_side_title(side1));
  666.  
  667.     /* insert in the side's side closeup list */
  668.     sidecloseup->next = side->ui->sidecloseuplist;
  669.     side->ui->sidecloseuplist = sidecloseup;
  670.  
  671.     XtPopup(sidecloseup->shell, XtGrabNone);
  672.  
  673.     return sidecloseup;
  674. }
  675.  
  676. void
  677. destroy_side_closeup(sidecloseup, side)
  678. SideCloseup *sidecloseup;
  679. Side *side;
  680. {
  681.     SideCloseup *sc;
  682.  
  683.     XtPopdown(sidecloseup->shell);
  684.     XtDestroyWidget(sidecloseup->shell);
  685.  
  686.     /* remove from the side's side closeup list */
  687.     if (side->ui->sidecloseuplist == sidecloseup) {
  688.     side->ui->sidecloseuplist = sidecloseup->next;
  689.     } else {
  690.     for_all_side_closeups(sc,side) {
  691.         if (sc->next == sidecloseup) {
  692.         sc->next = sidecloseup->next;
  693.         }
  694.     }
  695.     }
  696.     free(sidecloseup);
  697. }
  698.  
  699. void 
  700. draw_side_closeup(sidecloseup, side)
  701. SideCloseup *sidecloseup;
  702. Side *side;
  703. {
  704.     int u, numc[MAXUTYPES], numi[MAXUTYPES], i;
  705.     Side *side1 = sidecloseup->side, *side2;
  706.     Unit *unit;
  707.  
  708.     if (!active_display(side))
  709.       return;
  710.     if (!side_in_play(side1)
  711.     || !(side_controls_side(side, side1)
  712.          || endofgame
  713.          || side->designer)) {
  714.     /* If the side is no longer active, shut down the window. */
  715.     /* I don't know if this is a good idea.  Massimo */ 
  716.     destroy_side_closeup(sidecloseup,side);
  717.     return;
  718.     }
  719.  
  720.     if (longbuffer == NULL) {
  721.     longbuffer = (char *) xmalloc(longbuffer_length * sizeof(char));
  722.     }
  723.     longbuffer[0] = '\0';
  724.  
  725.     /* draw side name and class */
  726.     strcpy(buffer, short_side_title(side1));
  727.     if (side1->sideclass) {
  728.     tprintf(buffer, " (%s)", side1->sideclass);
  729.     }
  730.     buffer_append(1);
  731.     buffer_append(1);
  732.  
  733.     /* count and draw side's units (completed and incomplete) */
  734.     for_all_unit_types(u) {
  735.     numc[u] = 0;
  736.     numi[u] = 0;
  737.     }
  738.     for_all_side_units(side1,unit) {
  739.     if (completed(unit)) {
  740.         numc[unit->type]++;
  741.     } else {
  742.         numi[unit->type]++;
  743.     }
  744.     }
  745.     strcpy(buffer, "Completed units: ");
  746.     list_unit_types(buffer, numc);
  747.     buffer_append(1);
  748.     strcpy(buffer, "Units under construction: ");
  749.     list_unit_types(buffer, numi);
  750.     buffer_append(1);
  751.  
  752.     /* list side's tech level (if any) */
  753.     if (side1->tech != NULL) {
  754.     i = 0;
  755.     for_all_unit_types(u) {
  756.         i = i || side1->tech[u];
  757.     }
  758.     if (i) {
  759.         buffer_append(1);
  760.         strcpy(buffer, "Tech levels: ");
  761.         for_all_unit_types(u) {
  762.         if (side1->tech[u]) {
  763.             if (side1->tech[u]<u_tech_max(u)) {
  764.             tprintf(buffer, "%d/%d%1s ",
  765.                 side1->tech[u], u_tech_max(u),
  766.                 utype_name_n(u, 1));
  767.             } else {
  768.             tprintf(buffer, "%d%1s ", side1->tech[u],
  769.                 utype_name_n(u, 1));
  770.             }
  771.         }
  772.         }
  773.         buffer_append(1);
  774.     }
  775.     }
  776.  
  777.     /* list trusted sides (if any) */
  778.     i = 0;
  779.     for_all_sides(side2) 
  780.       i = i || (trusted_side(side1, side2) && side1 != side2);
  781.  
  782.     if (i) {
  783.     buffer_append(1);
  784.     strcpy(buffer, "Trusted sides: ");
  785.     for_all_sides(side2) {
  786.         if (trusted_side(side1, side2) && side1 != side2) 
  787.           tprintf(buffer, "%s, ", side_name(side2));
  788.     }
  789.     /* chop last two characters */
  790.     buffer[strlen(buffer)-2] = '\0';
  791.     buffer_append(1);
  792.     }
  793.  
  794.     XtVaSetValues(sidecloseup->info, XtNstring, longbuffer, NULL);
  795.  
  796.     RaiseWidget(sidecloseup->shell);
  797. }
  798.  
  799. /* manage a list (summary) of all unit closeups of a side */
  800.  
  801. static void
  802. add_to_closeup_summary(unitcloseup, side)
  803. UnitCloseup *unitcloseup;
  804. Side *side;
  805. {
  806.     CloseupSummary *summary = side->ui->closeupsummary;
  807.     Widget form, port;
  808.     char *label;
  809.  
  810.     if (summary == NULL) {
  811.     /* initialize and popup the summary */
  812.     summary = side->ui->closeupsummary =
  813.       (CloseupSummary *) xmalloc(sizeof(CloseupSummary));
  814.     summary->unitcloseups =
  815.       (UnitCloseup **) xmalloc(summary_size*sizeof(UnitCloseup *));
  816.     summary->number = 0;
  817.     summary->labels = (char **) xmalloc(summary_size*sizeof(char *));
  818.     
  819.     summary->shell =
  820.       XtVaCreatePopupShell("closeupList", topLevelShellWidgetClass,
  821.                    side->ui->shell,
  822.                    NULL);
  823.  
  824.     form =
  825.       XtVaCreateManagedWidget("form", formWidgetClass, summary->shell,
  826.                   NULL);
  827.  
  828.     summary->label =
  829.       XtVaCreateManagedWidget("label", labelWidgetClass, form,
  830.                   /* reserve space for label */
  831.                   XtNlabel,  "9999 unit closeups",
  832.                   XtNtop,    XawChainTop, 
  833.                   XtNbottom, XawChainTop, 
  834.                   XtNleft,   XawChainLeft, 
  835.                   XtNright,  XawChainLeft,
  836.                   NULL);
  837.  
  838.     port = 
  839.       XtVaCreateManagedWidget("port", viewportWidgetClass, form,
  840.                   XtNfromVert, summary->label,
  841.                   XtNallowVert, True,
  842.                   XtNtop,    XawChainTop, 
  843.                   XtNbottom, XawChainBottom, 
  844.                   XtNleft,   XawChainLeft, 
  845.                   XtNright,  XawChainRight, 
  846.                   NULL);
  847.  
  848.     summary->list =
  849.       XtVaCreateManagedWidget("list", listWidgetClass, port,
  850.                   XtNlongest, 0,
  851.                   NULL);
  852.     XtAddCallback(summary->list, XtNcallback,
  853.               (XtCallbackProc) summary_list_callback,
  854.               (XtPointer) NULL);
  855.  
  856.     XtPopup(summary->shell, XtGrabNone);
  857.     }
  858.  
  859.     summary->number++;
  860.     if (summary->number + 1 > summary_size) {
  861.     /* grow arrays */
  862.     summary_size *= 2;
  863.     summary->unitcloseups =
  864.       (UnitCloseup **) realloc(summary->unitcloseups,
  865.                    summary_size*sizeof(UnitCloseup *));
  866.     summary->labels =
  867.       (char **) realloc(summary->labels,
  868.                 summary_size*sizeof(char **));
  869.     }
  870.  
  871.     /* append new closeup */
  872.     summary->unitcloseups[summary->number-1] = unitcloseup;
  873.     label = summary->labels[summary->number-1] =
  874.       xmalloc((LISTLINE+1)*sizeof(char));
  875.     one_line_unit_summary(buffer, unitcloseup->unit, side, 1);
  876.     strncpy(label, buffer, LISTLINE);
  877.     label[LISTLINE] = '\0';
  878.  
  879.     XawListChange(summary->list, summary->labels,
  880.           summary->number, 0, True);
  881.  
  882.     sprintf(buffer,"%d unit closeup%s", summary->number,
  883.         (summary->number>1) ? "s" : "");
  884.     XtVaSetValues(summary->label, XtNlabel, buffer, NULL);
  885.  
  886.     /* don't raise this window */
  887. }
  888.  
  889. static void
  890. remove_from_closeup_summary(unitcloseup, side)
  891. UnitCloseup *unitcloseup;
  892. Side *side;
  893. {
  894.     CloseupSummary *summary = side->ui->closeupsummary;
  895.     int i, found;
  896.  
  897.     /* find and remove closeup */
  898.     found = 0;
  899.     for (i=0; i<summary->number; i++) {
  900.     if (summary->unitcloseups[i] == unitcloseup) {
  901.         found = 1;
  902.         free(summary->labels[i]);
  903.     }
  904.     if (found) {
  905.         summary->unitcloseups[i] = summary->unitcloseups[i+1];
  906.         summary->labels[i] = summary->labels[i+1];
  907.     }
  908.     }
  909.     summary->number--;
  910.  
  911.     XawListChange(summary->list, summary->labels,
  912.           summary->number, 0, True);
  913.  
  914.     sprintf(buffer,"%d unit closeup%s", summary->number,
  915.         (summary->number>1) ? "s" : "");
  916.     XtVaSetValues(summary->label, XtNlabel, buffer, NULL);
  917.  
  918.     if (summary->number==0) {
  919.     /* destroy window and cleanup summary */
  920.     XtPopdown(summary->shell);
  921.     XtDestroyWidget(summary->shell);
  922.     free(summary->unitcloseups);
  923.     free(summary->labels);
  924.     free(side->ui->closeupsummary);
  925.     side->ui->closeupsummary = NULL;
  926.     }
  927. }
  928.  
  929. /* callback for closeup list */
  930.  
  931. static void 
  932. summary_list_callback (w, dummy, list)
  933. Widget w;
  934. XtPointer dummy;
  935. XawListReturnStruct *list;
  936. {
  937.     Side *side;
  938.  
  939.     if (!find_side_via_widget(w, &side))
  940.       return;
  941.  
  942.     draw_unit_closeup(side->ui->closeupsummary->unitcloseups[list->list_index],
  943.               side);
  944. }
  945.  
  946. /* Redo the information in the unit's closeup. */
  947.  
  948. static void 
  949. unit_closeup_update (w, client_data, call_data)
  950. Widget w;
  951. XtPointer client_data;
  952. XtPointer call_data;
  953. {
  954.     Side *side;
  955.     UnitCloseup *unitcloseup;
  956.  
  957.     if (!find_side_via_widget(w, &side))
  958.       return;
  959.  
  960.     unitcloseup = find_unit_closeup_via_button(w, side);
  961.     draw_unit_closeup(unitcloseup, side);
  962. }
  963.  
  964. /* Raise the appropriate map and focus on the unit in the closeup. */
  965.  
  966. static void 
  967. unit_closeup_focus (w, client_data, call_data)
  968. Widget w;
  969. XtPointer client_data;
  970. XtPointer call_data;
  971. {
  972.     Side *side;
  973.     Map *map;
  974.     UnitCloseup *unitcloseup;
  975.  
  976.     if (!find_side_via_widget(w, &side))
  977.       return;
  978.  
  979.     unitcloseup = find_unit_closeup_via_button(w, side);
  980.     draw_unit_closeup(unitcloseup, side);
  981.     for_all_maps(side, map) {
  982.     if (map == unitcloseup->map) {
  983.         /* unitcloseup->map is up */
  984.         set_current_unit(side, map, unitcloseup->unit);
  985.         RaiseWidget(XtParent(map->mainwidget));
  986.         return;
  987.     }
  988.     }
  989.     /* choose another map */
  990.     if (side->ui->maps == NULL)
  991.       return;
  992.  
  993.     set_current_unit(side, side->ui->maps, unitcloseup->unit);
  994.     RaiseWidget(XtParent(side->ui->maps->mainwidget));
  995. }
  996.  
  997. static void 
  998. unit_closeup_close (w, client_data, call_data)
  999. Widget w;
  1000. XtPointer client_data;
  1001. XtPointer call_data;
  1002. {
  1003.     Side *side;
  1004.     UnitCloseup *unitcloseup;
  1005.  
  1006.     if (!find_side_via_widget(w, &side))
  1007.       return;
  1008.  
  1009.     unitcloseup = find_unit_closeup_via_button(w, side);
  1010.     destroy_unit_closeup(unitcloseup, side);
  1011. }
  1012.  
  1013. /* callbacks for side closeups */
  1014.  
  1015. static void 
  1016. side_closeup_close (w, client_data, call_data)
  1017. Widget w;
  1018. XtPointer client_data;
  1019. XtPointer call_data;
  1020. {
  1021.     Side *side;
  1022.     SideCloseup *sidecloseup;
  1023.  
  1024.     if (!find_side_via_widget(w, &side))
  1025.       return;
  1026.  
  1027.     sidecloseup = find_side_closeup_via_button(w, side);
  1028.     destroy_side_closeup(sidecloseup, side);
  1029. }
  1030.  
  1031. static void 
  1032. side_closeup_update (w, client_data, call_data)
  1033. Widget w;
  1034. XtPointer client_data;
  1035. XtPointer call_data;
  1036. {
  1037.     Side *side;
  1038.     SideCloseup *sidecloseup;
  1039.  
  1040.     if (!find_side_via_widget(w, &side))
  1041.       return;
  1042.  
  1043.     sidecloseup = find_side_closeup_via_button(w, side);
  1044.     draw_side_closeup(sidecloseup, side);
  1045. }
  1046.  
  1047. /* if a unit type filter is toggled, clear the "all types" filter */
  1048.  
  1049. static void 
  1050. side_closeup_type_callback (w, client_data, call_data)
  1051. Widget w;
  1052. XtPointer client_data;
  1053. XtPointer call_data;
  1054. {
  1055.     Side *side;
  1056.     SideCloseup *sidecloseup;
  1057.  
  1058.     if (!find_side_via_widget(w, &side))
  1059.       return;
  1060.  
  1061.     sidecloseup = find_side_closeup_via_button(XtParent(w), side);
  1062.     if (!sidecloseup)
  1063.       return;
  1064.     XtVaSetValues(sidecloseup->filter[0], XtNstate, False, NULL);
  1065. }
  1066.  
  1067. /* if the "all types" filter is set, clear all unit type filters */
  1068. /* if the "all types" filter is cleared, */
  1069. /* clear all unit type filters but set the first one */
  1070.  
  1071. static void 
  1072. side_closeup_all_types_callback (w, client_data, call_data)
  1073. Widget w;
  1074. XtPointer client_data;
  1075. XtPointer call_data;
  1076. {
  1077.     Side *side;
  1078.     SideCloseup *sidecloseup;
  1079.     int u;
  1080.     Boolean state;
  1081.  
  1082.     if (!find_side_via_widget(w, &side))
  1083.       return;
  1084.  
  1085.     sidecloseup = find_side_closeup_via_button(XtParent(w), side);
  1086.     if (!sidecloseup)
  1087.       return;
  1088.     XtVaGetValues(sidecloseup->filter[0], XtNstate, &state, NULL);
  1089.  
  1090.     for_all_unit_types(u) {
  1091.     XtVaSetValues(sidecloseup->filter[u+1], XtNstate, u==0 & !state, NULL);
  1092.     }
  1093. }
  1094.  
  1095. /* manage unit lists */
  1096.  
  1097. static void 
  1098. build_unit_list (w, client_data, call_data)
  1099. Widget w;
  1100. XtPointer client_data;
  1101. XtPointer call_data;
  1102. {
  1103.     Widget form, left, up;
  1104.     Side *side, *side1;
  1105.     SideCloseup *sidecloseup;
  1106.     Unit *unit;
  1107.     UnitList *unit_list;
  1108.     int i, u, size;
  1109.     Boolean filters[MAXFILTERS];
  1110.  
  1111.     if (!find_side_via_widget(w, &side))
  1112.       return;
  1113.  
  1114.     sidecloseup = find_side_closeup_via_button(w, side);
  1115.     for (i = 0; i < numutypes + OTHERFILTERS; ++i) {
  1116.     XtVaGetValues(sidecloseup->filter[i], XtNstate, &filters[i], NULL);
  1117.     }
  1118.     side1 = sidecloseup->side;
  1119.     unit_list = (UnitList *) xmalloc(sizeof(UnitList));
  1120.     unit_list->map = sidecloseup->map;
  1121.     unit_list->units  = (Unit **) xmalloc(unitlist_size * sizeof(Unit **));
  1122.     unit_list->labels = (char **) xmalloc(unitlist_size * sizeof(char **));
  1123.  
  1124.     /* build the filtered unit list */
  1125.     size = 0;
  1126.     for_all_side_units(side1, unit) {
  1127.     if (!alive(unit))
  1128.       continue;
  1129.     /* right type? */
  1130.     if (!filters[0] && !filters[unit->type+1])
  1131.       continue;
  1132.     /* completed? */
  1133.     if (filters[numutypes + 1] && !completed(unit))
  1134.       continue;
  1135.     /* waiting for orders? */
  1136.     if (filters[numutypes + 2] && 
  1137.         !(unit->plan &&
  1138.           !unit->plan->asleep &&
  1139.           !unit->plan->reserve &&
  1140.           !unit->plan->delayed &&
  1141.           unit->plan->waitingfortasks))
  1142.       continue;
  1143.     /* acp left? */
  1144.     if ((filters[numutypes+2] || filters[numutypes+3]) &&
  1145.         !(unit->act && unit->act->acp > 0))
  1146.       continue;
  1147.  
  1148.     /* unit is OK */
  1149.  
  1150.     if (size + 1 > unitlist_size) {
  1151.         /* grow arrays */
  1152.         unitlist_size *= 2;
  1153.         unit_list->units =
  1154.           (Unit **) realloc(unit_list->units,
  1155.                 unitlist_size*sizeof(Unit **));
  1156.         unit_list->labels =
  1157.           (char **) realloc(unit_list->labels,
  1158.                 unitlist_size*sizeof(char **));
  1159.     }
  1160.  
  1161.     /* append unit to list */
  1162.     unit_list->units[size] = unit;
  1163.     unit_list->labels[size] = xmalloc((LISTLINE+1)*sizeof(char));
  1164.     one_line_unit_summary(buffer, unit, side, 1);
  1165.     strncpy(unit_list->labels[size], buffer, LISTLINE);
  1166.     unit_list->labels[size][LISTLINE] = '\0';
  1167.     size++;
  1168.     }
  1169.  
  1170.     unit_list->number = size;
  1171.  
  1172.     /* create the popup */
  1173.     strcpy(buffer, "xconq unit list: ");
  1174.     strcat(buffer, side_adjective(side1));
  1175.     unit_list->shell =
  1176.       XtVaCreatePopupShell("unitList", topLevelShellWidgetClass,
  1177.                side->ui->shell,
  1178.                XtNtitle, buffer,
  1179.                XtNiconName, buffer,
  1180.                NULL);
  1181.  
  1182.     form =
  1183.       XtVaCreateManagedWidget("form", formWidgetClass, unit_list->shell,
  1184.                   NULL);
  1185.     left = up =
  1186.       XtVaCreateManagedWidget("flag", labelWidgetClass, form,
  1187.                   XtNbitmap, get_side_picture(side, side1),
  1188.                   XtNlabel, "",
  1189.                   XtNtop,    XawChainTop, 
  1190.                   XtNbottom, XawChainTop, 
  1191.                   XtNleft,   XawChainLeft, 
  1192.                   XtNright,  XawChainLeft,
  1193.                   NULL);
  1194.  
  1195.     left =
  1196.       XtVaCreateManagedWidget("side", labelWidgetClass, form,
  1197.                   XtNfromHoriz, left,
  1198.                   XtNlabel,  side_adjective(side1),
  1199.                   XtNtop,    XawChainTop, 
  1200.                   XtNbottom, XawChainTop, 
  1201.                   XtNleft,   XawChainLeft, 
  1202.                   XtNright,  XawChainLeft,
  1203.                   NULL);
  1204.  
  1205.     sprintf(buffer,"%d unit%s", size, (size>1) ? "s" : "");
  1206.     unit_list->label =
  1207.       XtVaCreateManagedWidget("label", labelWidgetClass, form,
  1208.                   XtNlabel,  buffer,
  1209.                   XtNfromHoriz, left,
  1210.                   XtNtop,    XawChainTop, 
  1211.                   XtNbottom, XawChainTop, 
  1212.                   XtNleft,   XawChainLeft, 
  1213.                   XtNright,  XawChainLeft,
  1214.                   NULL);
  1215.  
  1216.     /* show the filters used to produce the list */
  1217.     left = NULL;
  1218.     if (filters[0]) {
  1219.     left =
  1220.       XtVaCreateManagedWidget("allTypes", labelWidgetClass, form,
  1221.                   XtNfromVert, up,
  1222.                   XtNtop,    XawChainTop, 
  1223.                   XtNbottom, XawChainTop, 
  1224.                   XtNleft,   XawChainLeft, 
  1225.                   XtNright,  XawChainLeft,
  1226.                   NULL);
  1227.     } else {
  1228.     for_all_unit_types(u) {
  1229.         if (filters[u+1]) {
  1230.         left =
  1231.           XtVaCreateManagedWidget(utype_name_n(u,8),
  1232.                       labelWidgetClass, form,
  1233.                       XtNfromHoriz, left,
  1234.                       XtNfromVert, up,
  1235.                       XtNbitmap, get_unit_picture(u, side),
  1236.                       XtNtop,    XawChainTop, 
  1237.                       XtNbottom, XawChainTop, 
  1238.                       XtNleft,   XawChainLeft, 
  1239.                       XtNright,  XawChainLeft,
  1240.                       NULL);
  1241.         }
  1242.     }
  1243.     }
  1244.     if (filters[numutypes+1]) {
  1245.     left =
  1246.       XtVaCreateManagedWidget("completed", labelWidgetClass, form,
  1247.                   XtNfromHoriz, left,
  1248.                   XtNfromVert, up,
  1249.                   XtNtop,    XawChainTop, 
  1250.                   XtNbottom, XawChainTop, 
  1251.                   XtNleft,   XawChainLeft, 
  1252.                   XtNright,  XawChainLeft,
  1253.                   NULL);
  1254.     }
  1255.     if (filters[numutypes+2]) {
  1256.     left =
  1257.       XtVaCreateManagedWidget("waiting", labelWidgetClass, form,
  1258.                   XtNfromHoriz, left,
  1259.                   XtNfromVert, up,
  1260.                   XtNtop,    XawChainTop, 
  1261.                   XtNbottom, XawChainTop, 
  1262.                   XtNleft,   XawChainLeft, 
  1263.                   XtNright,  XawChainLeft,
  1264.                   NULL);
  1265.     }
  1266.     if (filters[numutypes+3]) {
  1267.         left =
  1268.           XtVaCreateManagedWidget("acpLeft", labelWidgetClass, form,
  1269.                       XtNfromHoriz, left,
  1270.                       XtNfromVert, up,
  1271.                       XtNtop,    XawChainTop, 
  1272.                       XtNbottom, XawChainTop, 
  1273.                       XtNleft,   XawChainLeft, 
  1274.                       XtNright,  XawChainLeft,
  1275.                       NULL);
  1276.     }
  1277.     if (left != NULL)
  1278.       up = left;
  1279.  
  1280.     if (size) {
  1281.     /* we fount some units, show them */
  1282.     up =
  1283.       XtVaCreateManagedWidget("port", viewportWidgetClass, form,
  1284.                   XtNfromVert, up,
  1285.                   XtNallowVert, True,
  1286.                   XtNtop,    XawChainTop, 
  1287.                   XtNbottom, XawChainBottom, 
  1288.                   XtNleft,   XawChainLeft, 
  1289.                   XtNright,  XawChainRight, 
  1290.                   NULL);
  1291.     unit_list->list =
  1292.       XtVaCreateManagedWidget("list", listWidgetClass, up,
  1293.                   XtNlongest, 0,
  1294.                   NULL);
  1295.     XawListChange(unit_list->list, unit_list->labels,
  1296.               size, 0, True);
  1297.     XtAddCallback(unit_list->list, XtNcallback,
  1298.               (XtCallbackProc) unit_list_callback, (XtPointer) NULL);
  1299.     } else {
  1300.     /* we fount no units, show a warning */
  1301.     unit_list->list = NULL;
  1302.     up =
  1303.       XtVaCreateManagedWidget("failed", labelWidgetClass, form,
  1304.                   XtNfromVert, up,
  1305.                   XtNtop,    XawChainTop, 
  1306.                   XtNbottom, XawChainBottom, 
  1307.                   XtNleft,   XawChainLeft, 
  1308.                   XtNright,  XawChainLeft, 
  1309.                   NULL);
  1310.     }
  1311.  
  1312.     left = unit_list->close =
  1313.       XtVaCreateManagedWidget("close", commandWidgetClass, form,
  1314.                   XtNfromVert,  up,
  1315.                   XtNtop,    XawChainBottom, 
  1316.                   XtNbottom, XawChainBottom, 
  1317.                   XtNleft,   XawChainLeft, 
  1318.                   XtNright,  XawChainLeft, 
  1319.                   NULL);
  1320.     XtAddCallback(unit_list->close, XtNcallback, unit_list_close, NULL);
  1321.  
  1322.     XtPopup(unit_list->shell, XtGrabNone);
  1323.  
  1324.     /* append to list */
  1325.     unit_list->next = side->ui->unitlistlist;
  1326.     side->ui->unitlistlist = unit_list;
  1327. }
  1328.  
  1329. static void 
  1330. unit_list_callback (w, dummy, list)
  1331. Widget w;
  1332. XtPointer dummy;
  1333. XawListReturnStruct *list;
  1334. {
  1335.     Side *side;
  1336.     UnitList *ul;
  1337.     UnitCloseup *unitcloseup;
  1338.     Unit *unit;
  1339.     Map *map;
  1340.     int i;
  1341.  
  1342.     if (!find_side_via_widget(w, &side))
  1343.       return;
  1344.     ul = find_unit_list_via_button(XtParent(w), side);
  1345.     if (ul == NULL)
  1346.       return;
  1347.  
  1348.     unit = ul->units[list->list_index];
  1349.     i = 0;
  1350.     for_all_maps(side, map) {
  1351.     if (map == ul->map)
  1352.       i = 1;
  1353.     }
  1354.     if (i) {
  1355.     map = ul->map;
  1356.     } else {
  1357.     /* ul->map not found */
  1358.     map = side->ui->maps;
  1359.     }
  1360.     if (map == NULL)
  1361.       return;
  1362.  
  1363.     unitcloseup = find_unit_closeup(unit, side);
  1364.     if (!unitcloseup)
  1365.       /* should never happen */
  1366.       unitcloseup = create_unit_closeup(unit, side, map);
  1367.     draw_unit_closeup(unitcloseup, side);
  1368. }
  1369.  
  1370. static void
  1371. unit_list_close (w, client_data, call_data)
  1372. Widget w;
  1373. XtPointer client_data;
  1374. XtPointer call_data;
  1375. {
  1376.     Side *side;
  1377.     UnitList *ul;
  1378.  
  1379.     if (!find_side_via_widget(w, &side))
  1380.       return;
  1381.  
  1382.     ul = find_unit_list_via_button(w, side);
  1383.     destroy_unit_list(ul, side);
  1384. }
  1385.  
  1386. void
  1387. destroy_unit_list(unit_list, side)
  1388. UnitList *unit_list;
  1389. Side *side;
  1390. {
  1391.     UnitList *ul;
  1392.     int i;
  1393.  
  1394.     XtPopdown(unit_list->shell);
  1395.     XtDestroyWidget(unit_list->shell);
  1396.  
  1397.     /* remove from list */
  1398.     if (side->ui->unitlistlist == unit_list) {
  1399.     side->ui->unitlistlist = unit_list->next;
  1400.     } else {
  1401.     for_all_unit_lists(ul,side) {
  1402.         if (ul->next == unit_list) {
  1403.         ul->next = unit_list->next;
  1404.         }
  1405.     }
  1406.     }
  1407.  
  1408.     for (i=0; i<ul->number; i++) 
  1409.       free(ul->labels[i]);
  1410.     free(ul->units);
  1411.     free(ul->labels);
  1412.     free(ul);
  1413. }
  1414.  
  1415. static UnitList *
  1416. find_unit_list_via_button(w, side)
  1417. Widget w;
  1418. Side *side;
  1419. {
  1420.     UnitList *ul;
  1421.     Widget shell = XtParent(XtParent(w));
  1422.  
  1423.     for_all_unit_lists(ul,side) {
  1424.     if (ul->shell == shell)
  1425.       return ul;
  1426.     }
  1427.     return NULL;
  1428.  
  1429. }
  1430.  
  1431. /* miscellanea of utilities; to be moved in the appropriate files */
  1432.  
  1433. /* pad str with blanks to reach a length n */
  1434. /* if min is positive, add a minimum of min blanks */
  1435. /* if min is negative, chop to n character, */
  1436. /* including a minimum of |min| blanks */
  1437.  
  1438. char *
  1439. pad_string(str, n, minim)
  1440. char *str;
  1441. int n;
  1442. int minim;
  1443. {
  1444.     int i;
  1445.     int len = strlen(str);
  1446.     int lim = ((minim >= 0) ? max(n, len + minim) : n);
  1447.  
  1448.     for (i = len; i < lim; i++) {
  1449.     str[i] = ' ';
  1450.     }
  1451.     str[lim] = '\0';
  1452.     if (minim < 0) {
  1453.     for (i = n + minim; i < n; i++) {
  1454.        str[i] = ' ';
  1455.        }
  1456.     } 
  1457.     return str;
  1458. }
  1459.  
  1460. void
  1461. hp_and_acp_desc(buf, unit, sep)
  1462. char *buf;
  1463. Unit *unit;
  1464. char *sep;
  1465. {
  1466.     /* Draw the unit's hit points and CP. */
  1467.     hp_desc(spbuf, unit, TRUE);
  1468.     strcat(buf, spbuf);
  1469.  
  1470.     /* Draw the unit's current ACP, if applicable. */
  1471.     if (u_acp(unit->type) > 0) {
  1472.     strcat(buf, sep);
  1473.     acp_desc(spbuf, unit, TRUE);
  1474.     strcat(buf, spbuf);
  1475.     }
  1476. }
  1477.  
  1478. /* a one-line description of unit and occupants */
  1479. /* add position info if pos!=0 */
  1480.  
  1481. void
  1482. one_line_unit_summary(buf, unit, side, pos)
  1483. char *buf;
  1484. Unit *unit;
  1485. Side *side;
  1486. int pos;
  1487. {
  1488.     Unit *occupant;
  1489.     int u, nums[MAXUTYPES];
  1490.  
  1491.     strcpy(buf, unit_handle(side, unit));
  1492.     if (pos) {
  1493.     if (unit->transport != NULL) {
  1494.         tprintf(buf, " in %s", short_unit_handle(unit->transport));
  1495.     } else {
  1496.         tprintf(buf, " in %s at %d,%d",
  1497.             t_type_name(terrain_at(unit->x, unit->y)),
  1498.             unit->x, unit->y);
  1499.     }
  1500.     }
  1501.     pad_string(buf, pos ? 45 : 40, -2);
  1502.     hp_and_acp_desc(buf, unit, "  ");
  1503.     if (unit->occupant != NULL) {
  1504.     /* Very briefly list the numbers and types of the occupants. */
  1505.     strcat(buf, "  Occ ");
  1506.     for_all_unit_types(u)
  1507.       nums[u] = 0;
  1508.     for_all_occupants(unit, occupant)
  1509.       nums[occupant->type]++;
  1510.     list_unit_types(buf, nums);
  1511.     }
  1512. }
  1513.  
  1514. /* produce a list of the number of units for each type */
  1515. /* from the given number array */
  1516.  
  1517. void
  1518. list_unit_types(buff, nums)
  1519. char *buff;
  1520. int nums[];
  1521. {
  1522.     int u, total = 0;
  1523.  
  1524.     for_all_unit_types(u) {
  1525.     if (nums[u] > 0) {
  1526.         total += nums[u];
  1527.         tprintf(buffer, "%d%1s ", nums[u], utype_name_n(u, 1));
  1528.     }
  1529.     }
  1530.     if (!total) {
  1531.     strcat(buff, "none  ");
  1532.     }
  1533. }
  1534.  
  1535. /* deiconify and rise the window corresponding to the given widget */
  1536. /* to be used with a shell window */
  1537.  
  1538. void 
  1539. RaiseWidget(w)
  1540. Widget w;
  1541. {
  1542.     XMapRaised(XtDisplay(w), XtWindow(w));
  1543. }
  1544.  
  1545. /* cache and return a unit picture */
  1546.  
  1547. Pixmap 
  1548. get_unit_picture(utype, side)
  1549. int utype;
  1550. Side *side;
  1551. {
  1552.     if (side->ui->unitpics[4][utype] == None) {
  1553.     Pixmap pic =
  1554.       XCreatePixmap(side->ui->dpy, side->ui->rootwin,
  1555.             min_w_for_unit_image, min_h_for_unit_image,
  1556.             DefaultDepth(side->ui->dpy, side->ui->screen));
  1557.     XSetForeground(side->ui->dpy, side->ui->gc, side->ui->bgcolor);
  1558.     XFillRectangle(side->ui->dpy, pic, side->ui->gc,
  1559.                0, 0, min_w_for_unit_image, min_h_for_unit_image);
  1560.     XSetForeground(side->ui->dpy, side->ui->gc, side->ui->fgcolor);
  1561.     draw_unit_image(side, pic, 0, 0,
  1562.             min_w_for_unit_image, min_h_for_unit_image,
  1563.             utype, -1, 1, 0);
  1564.     side->ui->unitpics[4][utype] = pic;
  1565.     }
  1566.     return side->ui->unitpics[4][utype];
  1567. }
  1568.  
  1569. /* cache and return a side picture (flag) */
  1570. /* should use mask somehow */
  1571.  
  1572. Pixmap 
  1573. get_side_picture(side, side1)
  1574. Side *side;
  1575. Side *side1;
  1576. {
  1577.     int s = side_number(side1);
  1578.  
  1579.     if (side->ui->emblempics[s] == None) {
  1580.     Pixmap pic;
  1581.     Image *img = best_image(side->ui->eimages[s],
  1582.                 min_w_for_unit_image, min_h_for_unit_image);
  1583.     if (img == NULL) {
  1584.         return None;
  1585.     }
  1586.  
  1587.     pic = XCreatePixmap(side->ui->dpy, side->ui->rootwin, img->w, img->h,
  1588.                 DefaultDepth(side->ui->dpy, side->ui->screen));
  1589.     XSetForeground(side->ui->dpy, side->ui->gc, side->ui->bgcolor);
  1590.     XFillRectangle(side->ui->dpy, pic, side->ui->gc,
  1591.                0, 0, img->w, img->h);
  1592.     XSetForeground(side->ui->dpy, side->ui->gc, side->ui->fgcolor);
  1593.     draw_side_emblem(side, pic, 0, 0, img->w, img->h, s, 0);
  1594.     side->ui->emblempics[s] = pic;
  1595.     }
  1596.     return side->ui->emblempics[s];
  1597. }
  1598.  
  1599. /* standing order support */
  1600.  
  1601. #define ORDER_COND_NUM 4
  1602. static char* order_cond[ORDER_COND_NUM] =
  1603.     { " none ", "  at  ", "  in  ", "within" };
  1604.  
  1605. static XtActionsRec xorders_actions[] = {
  1606.   { "DoneOrdersHelp", handle_done_orders_help },
  1607.   { "DoneStringSelect", handle_done_string_select },
  1608. };
  1609.  
  1610. static String helpText =
  1611. "Only one order at a time can be active (i.e. it can be edited);\n\
  1612. it is marked by an highlighted border.\n\
  1613. Clicking on the leftmost button of an order will toggle its activity.\n\
  1614. Deactivating an order will apply all changes.\n\
  1615. \n\
  1616. Clicking on an element of an active order will edit it.\n\
  1617. Clicking on an element of an inactive order will visualize it:\n\
  1618. if it is a cell address, the cell will be made current.\n\
  1619. \n\
  1620. The \"add\" button will add a new order.\n\
  1621. The \"delete\" button will delete the active order.\n\
  1622. The \"undo\" button will cancel all the changes to the active order.\n\
  1623. The \"quit\" button will popdown the orders window.";
  1624.  
  1625. void
  1626. create_orders_window(side, map)
  1627. Side *side;
  1628. Map *map;
  1629. {
  1630.     Widget form, up, left, port;
  1631.     StandingOrder *sorder;
  1632.     OrderInterface *ordi;
  1633.     int num;
  1634.  
  1635.     if (side->ui->sorder_edit == NULL)
  1636.       side->ui->sorder_edit = (StandingOrder *) xmalloc(sizeof(StandingOrder));
  1637.     if (side->ui->sorder_types_edit == NULL)
  1638.       side->ui->sorder_types_edit = (char *) xmalloc(numutypes*sizeof(char));
  1639.     if (side->ui->sorder_task_edit == NULL)
  1640.       side->ui->sorder_task_edit = (Task *) xmalloc(sizeof(Task));
  1641.  
  1642.     if (side->ui->orderlist == NULL) {
  1643.     /* initialize the order list */
  1644.     ordi = side->ui->orderlist;
  1645.     for (sorder = side->orders,  num = 0;
  1646.          sorder != NULL;
  1647.          sorder = sorder->next,  num++) {
  1648.  
  1649.         if (num) {
  1650.         ordi->next =
  1651.           (OrderInterface *) xmalloc(sizeof(OrderInterface));
  1652.         ordi = ordi->next;
  1653.         } else {
  1654.         side->ui->orderlist =
  1655.           (OrderInterface *) xmalloc(sizeof(OrderInterface));
  1656.         ordi = side->ui->orderlist;
  1657.         }
  1658.         ordi->sorder = sorder;
  1659.     }
  1660.     } else {
  1661.     num = count_sorder(side);
  1662.     }
  1663.  
  1664.     if (side->ui->orders_shell == NULL) {
  1665.         XtAppAddActions(thisapp, xorders_actions, XtNumber(xorders_actions));
  1666.  
  1667.     /* initialize the window */
  1668.     side->ui->orders_shell =
  1669.       XtVaCreatePopupShell("orders", topLevelShellWidgetClass,
  1670.                    side->ui->shell,
  1671.                    NULL);
  1672.  
  1673.     form =
  1674.       XtVaCreateManagedWidget("form", formWidgetClass,
  1675.                   side->ui->orders_shell,
  1676.                   NULL);
  1677.  
  1678.     side->ui->orders_label =
  1679.       XtVaCreateManagedWidget("label", labelWidgetClass, form,
  1680.                   /* reserve space for label */
  1681.                   XtNlabel,  "9999 standing orders",
  1682.                   XtNtop,    XawChainTop, 
  1683.                   XtNbottom, XawChainTop, 
  1684.                   XtNleft,   XawChainLeft, 
  1685.                   XtNright,  XawChainLeft,
  1686.                   NULL);
  1687.  
  1688.     port = 
  1689.       XtVaCreateManagedWidget("port", viewportWidgetClass, form,
  1690.                   XtNfromVert, side->ui->orders_label,
  1691.                   XtNallowVert, True,
  1692.                   XtNtop,    XawChainTop, 
  1693.                   XtNbottom, XawChainBottom, 
  1694.                   XtNleft,   XawChainLeft, 
  1695.                   XtNright,  XawChainRight, 
  1696.                   NULL);
  1697.  
  1698.     side->ui->orders_form =
  1699.       XtVaCreateManagedWidget("orders", formWidgetClass,
  1700.                   port,
  1701.                   NULL);
  1702.  
  1703.     up = NULL;
  1704.     for (ordi = side->ui->orderlist,  num = 0;
  1705.          ordi != NULL;
  1706.          ordi = ordi->next,  num++) {
  1707.         up = new_order_widgets(side, ordi, num, up);
  1708.     }
  1709.  
  1710.     left =
  1711.       XtVaCreateManagedWidget("help", commandWidgetClass, form,
  1712.                   XtNfromVert,  port,
  1713.                   XtNtop,    XawChainBottom, 
  1714.                   XtNbottom, XawChainBottom, 
  1715.                   XtNleft,   XawChainLeft, 
  1716.                   XtNright,  XawChainLeft, 
  1717.                   NULL);
  1718.     XtAddCallback(left, XtNcallback, orders_help_call, NULL);
  1719.  
  1720.     left =
  1721.       XtVaCreateManagedWidget("add", commandWidgetClass, form,
  1722.                   XtNfromVert,  port,
  1723.                   XtNfromHoriz, left,
  1724.                   XtNtop,    XawChainBottom, 
  1725.                   XtNbottom, XawChainBottom, 
  1726.                   XtNleft,   XawChainLeft, 
  1727.                   XtNright,  XawChainLeft, 
  1728.                   NULL);
  1729.     XtAddCallback(left, XtNcallback, orders_add_call, NULL);
  1730.  
  1731.     left =
  1732.       XtVaCreateManagedWidget("delete", commandWidgetClass, form,
  1733.                   XtNfromVert,  port,
  1734.                   XtNfromHoriz, left,
  1735.                   XtNtop,    XawChainBottom, 
  1736.                   XtNbottom, XawChainBottom, 
  1737.                   XtNleft,   XawChainLeft, 
  1738.                   XtNright,  XawChainLeft, 
  1739.                   NULL);
  1740.     XtAddCallback(left, XtNcallback, orders_delete_call, NULL);
  1741.  
  1742.     left =
  1743.       XtVaCreateManagedWidget("undo", commandWidgetClass, form,
  1744.                   XtNfromVert,  port,
  1745.                   XtNfromHoriz, left,
  1746.                   XtNtop,    XawChainBottom, 
  1747.                   XtNbottom, XawChainBottom, 
  1748.                   XtNleft,   XawChainLeft, 
  1749.                   XtNright,  XawChainLeft, 
  1750.                   NULL);
  1751.     XtAddCallback(left, XtNcallback, orders_undo_call, NULL);
  1752.  
  1753.     left =
  1754.       XtVaCreateManagedWidget("quit", commandWidgetClass, form,
  1755.                   XtNfromVert,  port,
  1756.                   XtNfromHoriz, left,
  1757.                   XtNtop,    XawChainBottom, 
  1758.                   XtNbottom, XawChainBottom, 
  1759.                   XtNleft,   XawChainLeft, 
  1760.                   XtNright,  XawChainLeft, 
  1761.                   NULL);
  1762.     XtAddCallback(left, XtNcallback, orders_quit_call, NULL);
  1763.     }
  1764.  
  1765.     sprintf(buffer, "%d standing order%s", num, (num==1) ? "" : "s");
  1766.     XtVaSetValues(side->ui->orders_label, XtNlabel, buffer, NULL);
  1767.     
  1768.     XtPopup(side->ui->orders_shell, XtGrabNone);
  1769.     RaiseWidget(side->ui->orders_shell);
  1770.  
  1771.     /* this is best done after the widgets has been realized 
  1772.        and their widths have been fixed */
  1773.     for (ordi = side->ui->orderlist;  ordi != NULL;  ordi = ordi->next) 
  1774.       update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
  1775.                ordi->sorder->task);
  1776.  
  1777. }
  1778.  
  1779. Widget
  1780. new_order_widgets(side, ordi, num, up)
  1781. Side *side;
  1782. OrderInterface *ordi;
  1783. int num;
  1784. Widget up;
  1785. {
  1786.     static Widget radio_group = NULL;
  1787.     Widget left;
  1788.     XrmDatabase xrdb;
  1789.     char *stype;
  1790.     XrmValue val;
  1791.     XColor color, junk;
  1792.     Colormap cmap;
  1793.     int res_found = 0;
  1794.     
  1795.     sprintf(spbuf, "order_%d", num+1);
  1796.     ordi->form = 
  1797.       XtVaCreateManagedWidget(spbuf, formWidgetClass,
  1798.                   side->ui->orders_form,
  1799.                   XtNfromVert, up,
  1800.                   XtNtop,    XawChainTop, 
  1801.                   XtNbottom, XawChainTop, 
  1802.                   XtNleft,   XawChainLeft, 
  1803.                   XtNright,  XawChainLeft, 
  1804.                   NULL);
  1805.     XtVaGetValues(ordi->form, XtNbackground, &(ordi->form_bg), NULL);
  1806.  
  1807.     /* get foreground pixel */
  1808.     xrdb = XtDatabase(side->ui->dpy);
  1809.     if (XrmGetResource(xrdb, "xconq*orders*orders.Form.foreground",
  1810.                "Xconq*orders*orders.Form.Foreground",
  1811.                &stype, &val)) {
  1812.     if (!strcmp(stype, "String")) {
  1813.         cmap = XDefaultColormap(side->ui->dpy, side->ui->screen);
  1814.         if (XAllocNamedColor(side->ui->dpy, cmap, val.addr,
  1815.                  &color, &junk)) {
  1816.         ordi->form_fg = color.pixel;
  1817.         res_found = 1;
  1818.         }
  1819.     }
  1820.     }
  1821.     if (!res_found) {
  1822.     /* fallback = border pixel */
  1823.     XtVaGetValues(ordi->form, XtNborderColor, &(ordi->form_fg), NULL);
  1824.     }
  1825.  
  1826.     left = ordi->toggle =
  1827.       XtVaCreateManagedWidget("toggle", toggleWidgetClass, ordi->form,
  1828.                   XtNlabel,  "",
  1829.                   XtNstate,  False,
  1830.                   XtNleft,   XawChainLeft, 
  1831.                   XtNright,  XawChainLeft, 
  1832.                   NULL);
  1833.     XtAddCallback(left, XtNcallback, order_toggle_call, NULL);
  1834.     if (num == 0)
  1835.       radio_group = left;
  1836.     XawToggleChangeRadioGroup(left, radio_group);
  1837.  
  1838.     left = ordi->types = 
  1839.       XtVaCreateManagedWidget("types", commandWidgetClass, ordi->form,
  1840.                   XtNbitmap, get_unit_picture(0, side),
  1841.                   XtNfromHoriz, left,
  1842.                   XtNleft,   XawChainLeft, 
  1843.                   XtNright,  XawChainLeft, 
  1844.                   NULL);
  1845.     XtAddCallback(left, XtNcallback, order_types_call, NULL);
  1846.  
  1847.     left = ordi->etype =
  1848.       XtVaCreateManagedWidget("etype", commandWidgetClass, ordi->form,
  1849.                   XtNlabel, "unknown",
  1850.                   XtNfromHoriz, left,
  1851.                   XtNleft,   XawChainLeft, 
  1852.                   XtNright,  XawChainLeft, 
  1853.                   NULL);
  1854.     XtAddCallback(left, XtNcallback, order_etype_call, NULL);
  1855.  
  1856.     left = ordi->eparms = 
  1857.       XtVaCreateManagedWidget("eparms", commandWidgetClass, ordi->form,
  1858.                   XtNlabel, "               ",
  1859.                   XtNfromHoriz, left,
  1860.                   XtNleft,   XawChainLeft, 
  1861.                   XtNright,  XawChainLeft, 
  1862.                   NULL);
  1863.     XtAddCallback(left, XtNcallback, order_eparms_call, NULL);
  1864.  
  1865.     left = ordi->task = 
  1866.       XtVaCreateManagedWidget("task", commandWidgetClass, ordi->form,
  1867.                   XtNlabel, "            ",
  1868.                   XtNfromHoriz, left,
  1869.                   XtNleft,   XawChainLeft, 
  1870.                   XtNright,  XawChainLeft, 
  1871.                   NULL);
  1872.     XtAddCallback(left, XtNcallback, order_task_call, NULL);
  1873.  
  1874.     left = ordi->tparms =
  1875.       XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
  1876.                   XtNlabel, "            ",
  1877.                   XtNfromHoriz, left,
  1878.                   XtNleft,   XawChainLeft, 
  1879.                   XtNright,  XawChainLeft, 
  1880.                   NULL);
  1881.     XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
  1882. #if 0
  1883.     if (ordi->sorder->etype == 1) {
  1884.     left = 
  1885.       XtVaCreateManagedWidget("etype", labelWidgetClass, ordi->form,
  1886.                   XtNlabel, "at",
  1887.                   XtNfromHoriz, left,
  1888.                   XtNleft,   XawChainLeft, 
  1889.                   XtNright,  XawChainLeft, 
  1890.                   NULL);
  1891.     
  1892.     sprintf(buffer, "%3d,%3d", ordi->sorder->a1, ordi->sorder->a2);
  1893.     left = ordi->eparms = 
  1894.       XtVaCreateManagedWidget("eparms", commandWidgetClass, ordi->form,
  1895.                   XtNlabel, buffer,
  1896.                   XtNfromHoriz, left,
  1897.                   XtNleft,   XawChainLeft, 
  1898.                   XtNright,  XawChainLeft, 
  1899.                   NULL);
  1900.     XtAddCallback(left, XtNcallback, order_eparms_call, NULL);
  1901.     } else {
  1902.     left = 
  1903.       XtVaCreateManagedWidget("etype", labelWidgetClass, ordi->form,
  1904.                   XtNlabel, "unknown",
  1905.                   XtNfromHoriz, left,
  1906.                   NULL);
  1907.     }
  1908.     
  1909.     if (ordi->sorder->task && ordi->sorder->task->type == TASK_MOVE_TO) {
  1910.     left = ordi->task = 
  1911.       XtVaCreateManagedWidget("task", labelWidgetClass, ordi->form,
  1912.                   XtNlabel, "move-to",
  1913.                   XtNfromHoriz, left,
  1914.                   XtNleft,   XawChainLeft, 
  1915.                   XtNright,  XawChainLeft, 
  1916.                   NULL);
  1917.     
  1918.     sprintf(buffer, "%3d,%3d",
  1919.         ordi->sorder->task->args[0], ordi->sorder->task->args[1]);
  1920.     left = ordi->tparms =
  1921.       XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
  1922.                   XtNlabel, buffer,
  1923.                   XtNfromHoriz, left,
  1924.                   XtNleft,   XawChainLeft, 
  1925.                   XtNright,  XawChainLeft, 
  1926.                   NULL);
  1927.     XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
  1928.     } else {
  1929.     left = ordi->task = 
  1930.       XtVaCreateManagedWidget("task", labelWidgetClass, ordi->form,
  1931.                   XtNlabel, "unknown",
  1932.                   XtNfromHoriz, left,
  1933.                   XtNleft,   XawChainLeft, 
  1934.                   XtNright,  XawChainLeft, 
  1935.                   NULL);
  1936.     left = ordi->tparms =
  1937.       XtVaCreateManagedWidget("tparms", commandWidgetClass, ordi->form,
  1938.                   XtNlabel, "     ",
  1939.                   XtNfromHoriz, left,
  1940.                   XtNleft,   XawChainLeft, 
  1941.                   XtNright,  XawChainLeft, 
  1942.                   NULL);
  1943.     XtAddCallback(left, XtNcallback, order_tparms_call, NULL);
  1944.     }
  1945. #endif
  1946.  
  1947.     return ordi->form;
  1948. }
  1949.  
  1950. void
  1951. sorder_cond_name(buf, sorder, side)
  1952. char *buf;
  1953. StandingOrder *sorder;
  1954. Side *side;
  1955. {
  1956.     switch (sorder->etype) {
  1957.     case 0:
  1958.     strcpy(buf, "            ");
  1959.     return;
  1960.     case 1:
  1961.     sprintf(buf, "%3d,%3d      ", sorder->a1, sorder->a2);
  1962.     return;
  1963.     /* let unit_handle and find_unit handle exceptions */
  1964.     case 2:
  1965. /*    strcpy(buf, unit_handle(side, find_unit(sorder->a1))); */
  1966.     strcpy(buf, short_unit_handle(find_unit(sorder->a1)));
  1967.     if (strlen(buf) < 12)
  1968.       strncat(buf, "            ", 12 - strlen(buf));
  1969.     return;
  1970.     case 3:
  1971.     sprintf(buf, "%2d of %3d,%3d", sorder->a3, sorder->a1, sorder->a2);
  1972.     }
  1973. }
  1974.  
  1975. void
  1976. update_order_widgets(side, ordi, sorder, types, task)
  1977. Side *side;
  1978. OrderInterface *ordi;
  1979. StandingOrder *sorder;
  1980. char *types;
  1981. Task *task;
  1982. {
  1983.     int u;
  1984.     char *lab;
  1985.     Pixmap icon = None;
  1986.     
  1987.     for_all_unit_types(u) {
  1988.     if (types[u]) {
  1989.         icon = get_unit_picture(u, side);
  1990.     }
  1991.     }
  1992.     XtVaSetValues(ordi->types, XtNbitmap, icon, NULL);
  1993.  
  1994.     if (sorder->etype >= 0 && sorder->etype < ORDER_COND_NUM) {
  1995.     lab = order_cond[(int) sorder->etype];
  1996.     } else {
  1997.     lab = "unknown";
  1998.     }
  1999.     XtVaSetValues(ordi->etype, XtNlabel, lab, NULL);
  2000.  
  2001.     sorder_cond_name(buffer, sorder, side);
  2002.     XtVaSetValues(ordi->eparms, XtNlabel, buffer, NULL);
  2003.  
  2004.     if (task) {
  2005.     XtVaSetValues(ordi->task, XtNlabel, taskdefns[task->type].name, NULL);
  2006.  
  2007.     /* get task description, chop task name and separator */
  2008.     task_desc(buffer, task);
  2009.     lab = buffer + strlen(taskdefns[task->type].name);
  2010.     while (*lab == ' ' || *lab == ',')
  2011.         lab++;
  2012.     XtVaSetValues(ordi->tparms, XtNlabel, lab, NULL);
  2013.     } else {
  2014.     XtVaSetValues(ordi->task,   XtNlabel, "none        ", NULL);
  2015.     XtVaSetValues(ordi->tparms, XtNlabel, "            ", NULL);
  2016.     }
  2017. }
  2018.  
  2019. /* callbacks for orders */
  2020.  
  2021. static void 
  2022. orders_help_call (w, client_data, call_data)
  2023. Widget w;
  2024. XtPointer client_data;
  2025. XtPointer call_data;
  2026. {
  2027.     Side *side;
  2028.     Widget form, done, text;
  2029.  
  2030.     if (!find_side_via_widget(w, &side))
  2031.       return;
  2032.  
  2033.     if (!side->ui->orders_help_shell) {
  2034.     side->ui->orders_help_shell =
  2035.       XtVaCreatePopupShell("ordersHelp", topLevelShellWidgetClass,
  2036.                    side->ui->shell,
  2037.                    NULL);
  2038.     form =
  2039.       XtVaCreateManagedWidget("form", formWidgetClass,
  2040.                   side->ui->orders_help_shell,
  2041.                   NULL);
  2042.     text =
  2043.       XtVaCreateManagedWidget("text", labelWidgetClass, form,
  2044.                   XtNlabel, helpText,
  2045.                   NULL);
  2046.     done =
  2047.       XtVaCreateManagedWidget("done", commandWidgetClass, form,
  2048.                   XtNfromVert, text,
  2049.                   NULL);
  2050.     XtAddCallback(done, XtNcallback, orders_done_help_call, NULL);
  2051.     }
  2052.  
  2053.     XtPopup(side->ui->orders_help_shell, XtGrabNone);
  2054. }
  2055.  
  2056. static void 
  2057. orders_done_help_call (w, client_data, call_data)
  2058. Widget w;
  2059. XtPointer client_data;
  2060. XtPointer call_data;
  2061. {
  2062.     Side *side;
  2063.  
  2064.     if (!find_side_via_widget(w, &side))
  2065.       return;
  2066.  
  2067.     if (side->ui->orders_help_shell)
  2068.       XtPopdown(side->ui->orders_help_shell);
  2069. }
  2070.  
  2071. static void
  2072. handle_done_orders_help(w, event, params, numparms)
  2073. Widget w;
  2074. XEvent *event;
  2075. String *params;
  2076. Cardinal *numparms;
  2077. {
  2078.     Side *side;
  2079.  
  2080.     if (!find_side_via_widget(w, &side))
  2081.       return;
  2082.  
  2083.     if (side->ui->orders_help_shell)
  2084.       XtPopdown(side->ui->orders_help_shell);
  2085. }
  2086.  
  2087. static void 
  2088. orders_add_call (w, client_data, call_data)
  2089. Widget w;
  2090. XtPointer client_data;
  2091. XtPointer call_data;
  2092. {
  2093.     StandingOrder *sorder;
  2094.     OrderInterface *ordi;
  2095.     Side *side;
  2096.     Widget up;
  2097.     int num;
  2098.  
  2099.     if (!find_side_via_widget(w, &side))
  2100.       return;
  2101.  
  2102.     /* disable active order */
  2103.     ordi = active_ordi(side);
  2104.     if (ordi) {
  2105.     XtVaSetValues(ordi->toggle, XtNstate, False, NULL);
  2106.     order_toggle_call(ordi->toggle, NULL, NULL);
  2107.     }
  2108.  
  2109.     /* get last sorder and ordi */
  2110.     for (sorder = side->orders,  num = 0,  ordi = side->ui->orderlist;
  2111.      sorder != NULL && sorder->next != NULL;
  2112.      sorder = sorder->next,  num++,  ordi = ordi->next);
  2113.  
  2114.     if (sorder == NULL) {
  2115.     up = NULL;
  2116.     ordi = side->ui->orderlist =
  2117.       (OrderInterface *) xmalloc(sizeof(OrderInterface));
  2118.     } else {
  2119.     /* sanity checks */
  2120.     if (sorder->next != NULL || sorder != side->last_order ||
  2121.         ordi   == NULL || ordi->next   != NULL) 
  2122.       run_error("Sanity check failed in orders_add_call");
  2123.  
  2124.     up = ordi->form;
  2125.     ordi->next = (OrderInterface *) xmalloc(sizeof(OrderInterface));
  2126.     ordi = ordi->next;
  2127.     }
  2128.  
  2129.     /* generate a "blank" order */
  2130.     sprintf(buffer, "%s at 0,0 move-to 0,0", u_type_name(0));
  2131.     parse_standing_order(side, buffer);
  2132.     ordi->sorder = side->orders;
  2133.  
  2134.     /* re-create orders window */
  2135.     XtPopdown(side->ui->orders_shell);
  2136.     XtDestroyWidget(side->ui->orders_shell);
  2137.     side->ui->orders_shell = NULL;
  2138.     create_orders_window(side, side->ui->maps);
  2139.  
  2140.     /* activate new order */
  2141.     XtVaSetValues(ordi->toggle, XtNstate, True, NULL);
  2142.     order_toggle_call(ordi->toggle, NULL, NULL);
  2143. }
  2144.  
  2145. static void 
  2146. orders_delete_call (w, client_data, call_data)
  2147. Widget w;
  2148. XtPointer client_data;
  2149. XtPointer call_data;
  2150. {
  2151.     Side *side;
  2152.     OrderInterface *ordi, *activeo;
  2153.     StandingOrder *sorder;
  2154.     
  2155.     if (!find_side_via_widget(w, &side))
  2156.       return;
  2157.  
  2158.     activeo = active_ordi(side);
  2159.     if (activeo == NULL) 
  2160.       return;
  2161.  
  2162.     /* remove sorder and ordi */
  2163.     if (side->ui->orderlist == activeo) {
  2164.     side->ui->orderlist = side->ui->orderlist->next;
  2165.     side->orders = side->orders->next;
  2166.     if (side->orders == NULL) {
  2167.         side->last_order = NULL;
  2168.     }
  2169.     } else {
  2170.     for (sorder = side->orders,  ordi = side->ui->orderlist;
  2171.          sorder != NULL && sorder->next != NULL;
  2172.          sorder = sorder->next,  ordi = ordi->next) {
  2173.         if (ordi->next == activeo) {
  2174.         ordi->next = ordi->next->next;
  2175.         if (sorder->next == side->last_order) {
  2176.             side->last_order = sorder;
  2177.         }
  2178.         sorder->next = sorder->next->next;
  2179.         break;
  2180.         }
  2181.     }
  2182.     }
  2183.  
  2184.     /* re-create orders window */
  2185.     XtPopdown(side->ui->orders_shell);
  2186.     XtDestroyWidget(side->ui->orders_shell);
  2187.     side->ui->orders_shell = NULL;
  2188.     create_orders_window(side, side->ui->maps);
  2189. }
  2190.  
  2191. static void 
  2192. orders_undo_call (w, client_data, call_data)
  2193. Widget w;
  2194. XtPointer client_data;
  2195. XtPointer call_data;
  2196. {
  2197.     Side *side;
  2198.     OrderInterface *ordi;
  2199.  
  2200.     if (!find_side_via_widget(w, &side))
  2201.       return;
  2202.  
  2203.     ordi = active_ordi(side);
  2204.     if (ordi == NULL)
  2205.       return;
  2206.  
  2207.     /* copy standing order */
  2208.     *(side->ui->sorder_edit) = *(ordi->sorder);
  2209.     memcpy(side->ui->sorder_types_edit, ordi->sorder->types,
  2210.        numutypes*sizeof(char));
  2211.     *(side->ui->sorder_task_edit) = *(ordi->sorder->task);
  2212.     update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
  2213.              ordi->sorder->task);
  2214. }
  2215.  
  2216. static void 
  2217. orders_quit_call(w, client_data, call_data)
  2218. Widget w;
  2219. XtPointer client_data;
  2220. XtPointer call_data;
  2221. {
  2222.     Side *side;
  2223.  
  2224.     if (!find_side_via_widget(w, &side))
  2225.       return;
  2226.  
  2227.     XtPopdown(side->ui->orders_shell);
  2228.  
  2229.     if (side->ui->orders_help_shell)
  2230.       XtPopdown(side->ui->orders_help_shell);
  2231. }
  2232.  
  2233.  
  2234. static void 
  2235. order_toggle_call (w, client_data, call_data)
  2236. Widget w;
  2237. XtPointer client_data;
  2238. XtPointer call_data;
  2239. {
  2240.     Side *side;
  2241.     Boolean state;
  2242.     OrderInterface *ordi;
  2243.  
  2244.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2245.       return;
  2246.  
  2247.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2248.     if (state) {
  2249.     XtVaSetValues(ordi->form, XtNbackground, ordi->form_fg, NULL);
  2250.  
  2251.     /* copy standing order */
  2252.     side->ui->ordi_edit = ordi;
  2253.     *(side->ui->sorder_edit) = *(ordi->sorder);
  2254.     memcpy(side->ui->sorder_types_edit, ordi->sorder->types,
  2255.            numutypes*sizeof(char));
  2256.     *(side->ui->sorder_task_edit) = *(ordi->sorder->task);
  2257.     } else {
  2258.     XtVaSetValues(ordi->form, XtNbackground, ordi->form_bg, NULL);
  2259.  
  2260.     /* update standing order */
  2261.     *(ordi->sorder) = *(side->ui->sorder_edit);
  2262.     memcpy(ordi->sorder->types, side->ui->sorder_types_edit,
  2263.            numutypes*sizeof(char));
  2264.     *(ordi->sorder->task) = *(side->ui->sorder_task_edit);
  2265.     update_order_widgets(side, ordi, ordi->sorder, ordi->sorder->types,
  2266.                  ordi->sorder->task);
  2267.     }
  2268. }
  2269.  
  2270. static void 
  2271. order_etype_call (w, client_data, call_data)
  2272. Widget w;
  2273. XtPointer client_data;
  2274. XtPointer call_data;
  2275. {
  2276.     Side *side;
  2277.     OrderInterface *ordi;
  2278.     Boolean state;
  2279.     Map *map;
  2280.     Position x, y;
  2281.     int i;
  2282.  
  2283.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2284.       return;
  2285.     map = side->ui->maps;
  2286.  
  2287.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2288.  
  2289.     if (!state) 
  2290.     return;
  2291.  
  2292.     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
  2293.     i = cond_select_popup(side, x+32, y+32);
  2294.     if (i >= 0  &&  i < ORDER_COND_NUM && i != side->ui->sorder_edit->etype) {
  2295.     XtVaSetValues(ordi->etype, XtNlabel, order_cond[i], NULL);
  2296.     side->ui->sorder_edit->etype = i;
  2297.     side->ui->sorder_edit->a1 = 0;
  2298.     side->ui->sorder_edit->a2 = 0;
  2299.     side->ui->sorder_edit->a3 = 0;
  2300.     sorder_cond_name(buffer, side->ui->sorder_edit, side);
  2301.     XtVaSetValues(ordi->eparms, XtNlabel, buffer, NULL);
  2302.     }
  2303. }
  2304.  
  2305. static void 
  2306. order_eparms_call (w, client_data, call_data)
  2307. Widget w;
  2308. XtPointer client_data;
  2309. XtPointer call_data;
  2310. {
  2311.     Side *side;
  2312.     OrderInterface *ordi;
  2313.     Boolean state;
  2314.     Map *map;
  2315.     Position x, y;
  2316.     Unit *unit;
  2317.  
  2318.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2319.       return;
  2320.     map = side->ui->maps;
  2321.  
  2322.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2323.  
  2324.     if (state) {
  2325.     /* edit */
  2326.     switch (side->ui->sorder_edit->etype) {
  2327.     case 1:
  2328.         set_cell_from_map(side, map,
  2329.                   "select origin cell, then press space",
  2330.                   (void *) &side->ui->sorder_edit->a1,
  2331.                   (void *) &side->ui->sorder_edit->a2,
  2332.                   sizeof(side->ui->sorder_edit->a1));
  2333.         break;
  2334.     case 2:
  2335.         set_unit_from_map (side, map, 
  2336.                    "select origin unit, then press space",
  2337.                    (void *) &side->ui->sorder_edit->a1);
  2338.         break;
  2339.     case 3:
  2340.         XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
  2341.         side->ui->sorder_edit->a3 =
  2342.           integer_select_popup(side, x+32, y+32, side->ui->sorder_edit->a3,
  2343.                    "enter origin radius");
  2344.         if (side->ui->sorder_edit->a3<0)
  2345.           side->ui->sorder_edit->a3 = 0;
  2346.         set_cell_from_map(side, map,
  2347.                   "select origin center, then press space",
  2348.                   (void *) &side->ui->sorder_edit->a1,
  2349.                   (void *) &side->ui->sorder_edit->a2,
  2350.                   sizeof(side->ui->sorder_edit->a1));
  2351.         break;
  2352.     }
  2353.     } else {
  2354.     /* display */
  2355.     if (ordi->sorder->etype == 1 || ordi->sorder->etype == 3) {
  2356.         if (in_area(ordi->sorder->a1, ordi->sorder->a2)) {
  2357.         map->curx = ordi->sorder->a1;
  2358.         map->cury = ordi->sorder->a2;
  2359.         map->curunit = NULL;
  2360.         recenter(side, map, ordi->sorder->a1, ordi->sorder->a2);
  2361.         do_x_flash(side, map);
  2362.         } else {
  2363.         beep(side);
  2364.         }
  2365.     } else if (ordi->sorder->etype == 2) {
  2366.         if ((unit = find_unit(ordi->sorder->a1)) != NULL) {
  2367.             set_current_unit(side, map, unit);
  2368.         map->curx = unit->x;  map->cury = unit->y;
  2369.         recenter(side, map, unit->x, unit->y);
  2370.         do_x_flash(side, map);
  2371.         } else {
  2372.         beep(side);
  2373.         }
  2374.     }
  2375.     }
  2376. }
  2377.  
  2378. static void 
  2379. order_task_call (w, client_data, call_data)
  2380. Widget w;
  2381. XtPointer client_data;
  2382. XtPointer call_data;
  2383. {
  2384.     Side *side;
  2385.     OrderInterface *ordi;
  2386.     Boolean state;
  2387.     Map *map;
  2388.     Position x, y;
  2389.     int i, type;
  2390.  
  2391.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2392.       return;
  2393.     map = side->ui->maps;
  2394.  
  2395.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2396.  
  2397.     if (!state) 
  2398.       return;
  2399.  
  2400.     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
  2401.     type = task_select_popup(side, x+32, y+32);
  2402.     if (type<0 || type>=num_tasks() || type==side->ui->sorder_task_edit->type)
  2403.       return;
  2404.  
  2405.     side->ui->sorder_task_edit->type = type;
  2406.     for (i=0; i<MAXTASKARGS; i++)
  2407.       side->ui->sorder_task_edit->args[i] = 0;
  2408.     side->ui->sorder_task_edit->execnum = 0;
  2409.     side->ui->sorder_task_edit->retrynum = 0;
  2410.  
  2411.     update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
  2412.              side->ui->sorder_types_edit,
  2413.              side->ui->sorder_task_edit);
  2414.  
  2415. }
  2416.  
  2417. static void 
  2418. order_types_call (w, client_data, call_data)
  2419. Widget w;
  2420. XtPointer client_data;
  2421. XtPointer call_data;
  2422. {
  2423.     Side *side;
  2424.     OrderInterface *ordi;
  2425.     Boolean state;
  2426.     Pixmap icon;
  2427.     int i, oldu = 0, newu;
  2428.     Position x, y;
  2429.  
  2430.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2431.       return;
  2432.  
  2433.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2434.     if (!state)
  2435.       return;
  2436.  
  2437.     for_all_unit_types(i) {
  2438.     if (side->ui->sorder_types_edit[i]) {
  2439.         oldu = i;
  2440.         break;
  2441.     }
  2442.     }
  2443.  
  2444.     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
  2445.     newu = utype_select_popup(side, x+32, y+32);
  2446.     if (newu != NONUTYPE) {
  2447.     icon = get_unit_picture(newu, side);
  2448.     XtVaSetValues(ordi->types, XtNbitmap, icon, NULL);
  2449.     side->ui->sorder_types_edit[oldu] = 0;
  2450.     side->ui->sorder_types_edit[newu] = 1;
  2451.     }
  2452. }
  2453.  
  2454. static int select_loop, select_cond, select_task, select_utype, select_dir;
  2455.  
  2456. int
  2457. cond_select_popup(side, x, y)
  2458. Side *side;
  2459. Position x;
  2460. Position y;
  2461. {
  2462.     Widget box, shell, command;
  2463.     int i;
  2464.  
  2465.     select_cond = ORDER_COND_NUM;
  2466.  
  2467.     shell =
  2468.       XtVaCreatePopupShell("condSelect", transientShellWidgetClass,
  2469.                side->ui->shell,
  2470.                XtNx, x,
  2471.                XtNy, y,
  2472.                NULL);
  2473.     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
  2474.                NULL);
  2475.  
  2476.     for (i=0; i<ORDER_COND_NUM; i++) {
  2477.     command =
  2478.       XtVaCreateManagedWidget(order_cond[i], commandWidgetClass, box,
  2479.                   NULL);
  2480.     XtAddCallback(command, XtNcallback, cond_select_call,
  2481.               (XtPointer) i);
  2482.     }
  2483.     command =
  2484.       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
  2485.                   NULL);
  2486.     XtAddCallback(command, XtNcallback, cond_select_call,
  2487.           (XtPointer) ORDER_COND_NUM); 
  2488.  
  2489.     XtPopup(shell, XtGrabExclusive);
  2490.  
  2491.     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
  2492.  
  2493.     /* replacement for XtAppMainLoop(thisapp): */
  2494.     select_loop = 1;
  2495.     while (select_loop) {
  2496.     XEvent event;
  2497.  
  2498.     XtAppNextEvent(thisapp, &event);
  2499.     XtDispatchEvent(&event);
  2500.     }
  2501.     XtPopdown(shell);
  2502.     XtDestroyWidget(shell);
  2503.  
  2504.     return select_cond;
  2505. }
  2506.  
  2507. static void 
  2508. cond_select_call (w, client_data, call_data)
  2509. Widget w;
  2510. XtPointer client_data;
  2511. XtPointer call_data;
  2512. {
  2513.     int i;
  2514.  
  2515.     for (i=0; i<ORDER_COND_NUM; i++) {
  2516.     if (client_data == (XtPointer) i) {
  2517.         select_cond = i;
  2518.         select_loop = 0;
  2519.         return;
  2520.     }
  2521.     }
  2522.     select_cond = ORDER_COND_NUM;
  2523.     select_loop = 0;
  2524.     return;
  2525. }
  2526.  
  2527. int
  2528. task_select_popup(side, x, y)
  2529. Side *side;
  2530. Position x;
  2531. Position y;
  2532. {
  2533.     Widget box, shell, command;
  2534.     int i;
  2535.  
  2536.     select_task = -1;
  2537.  
  2538.     shell =
  2539.       XtVaCreatePopupShell("taskSelect", transientShellWidgetClass,
  2540.                side->ui->shell,
  2541.                XtNx, x,
  2542.                XtNy, y,
  2543.                NULL);
  2544.     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
  2545.                NULL);
  2546.  
  2547.     for (i = 0; taskdefns[i].name != NULL; i++) {
  2548.         command =
  2549.       XtVaCreateManagedWidget(taskdefns[i].name, commandWidgetClass,
  2550.                   box, NULL);
  2551.     XtAddCallback(command, XtNcallback, task_select_call,
  2552.               (XtPointer) i);
  2553.     }
  2554.     command =
  2555.       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
  2556.                   NULL);
  2557.     XtAddCallback(command, XtNcallback, task_select_call,
  2558.           (XtPointer) -1); 
  2559.  
  2560.     XtPopup(shell, XtGrabExclusive);
  2561.  
  2562.     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
  2563.  
  2564.     /* replacement for XtAppMainLoop(thisapp): */
  2565.     select_loop = 1;
  2566.     while (select_loop) {
  2567.     XEvent event;
  2568.  
  2569.     XtAppNextEvent(thisapp, &event);
  2570.     XtDispatchEvent(&event);
  2571.     }
  2572.     XtPopdown(shell);
  2573.     XtDestroyWidget(shell);
  2574.  
  2575.     return select_task;
  2576. }
  2577.  
  2578. static void 
  2579. task_select_call (w, client_data, call_data)
  2580. Widget w;
  2581. XtPointer client_data;
  2582. XtPointer call_data;
  2583. {
  2584.     int i;
  2585.  
  2586.     for (i = 0; taskdefns[i].name != NULL; i++) {
  2587.     if (client_data == (XtPointer) i) {
  2588.         select_task = i;
  2589.         select_loop = 0;
  2590.         return;
  2591.     }
  2592.     }
  2593.     select_task = -1;
  2594.     select_loop = 0;
  2595.     return;
  2596. }
  2597.  
  2598. int
  2599. utype_select_popup(side, x, y)
  2600. Side *side;
  2601. Position x;
  2602. Position y;
  2603. {
  2604.     Widget box, shell, command;
  2605.     Pixmap icon;
  2606.     int u;
  2607.  
  2608.     select_utype = NONUTYPE;
  2609.  
  2610.     shell =
  2611.       XtVaCreatePopupShell("utypeSelect", transientShellWidgetClass,
  2612.                side->ui->shell,
  2613.                XtNx, x,
  2614.                XtNy, y,
  2615.                NULL);
  2616.     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
  2617.                NULL);
  2618.  
  2619.     for_all_unit_types(u) {
  2620.     icon = get_unit_picture(u, side);
  2621.     build_name(buffer, "", u_type_name(u));
  2622.     command =
  2623.        XtVaCreateManagedWidget(buffer, commandWidgetClass, box,
  2624.                    XtNlabel, "",
  2625.                    XtNbitmap, icon,
  2626.                    NULL);
  2627.     XtAddCallback(command, XtNcallback, utype_select_call,
  2628.               (XtPointer) u);
  2629.     }
  2630.     command =
  2631.       XtVaCreateManagedWidget("cancel", commandWidgetClass, box,
  2632.                   NULL);
  2633.     XtAddCallback(command, XtNcallback, utype_select_call,
  2634.           (XtPointer) NONUTYPE); 
  2635.  
  2636.     XtPopup(shell, XtGrabExclusive);
  2637.  
  2638.     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
  2639.  
  2640.     /* replacement for XtAppMainLoop(thisapp): */
  2641.     select_loop = 1;
  2642.     while (select_loop) {
  2643.     XEvent event;
  2644.  
  2645.     XtAppNextEvent(thisapp, &event);
  2646.     XtDispatchEvent(&event);
  2647.     }
  2648.     XtPopdown(shell);
  2649.     XtDestroyWidget(shell);
  2650.  
  2651.     return select_utype;
  2652. }
  2653.  
  2654. static void 
  2655. utype_select_call (w, client_data, call_data)
  2656. Widget w;
  2657. XtPointer client_data;
  2658. XtPointer call_data;
  2659. {
  2660.     int u;
  2661.  
  2662.     for_all_unit_types(u) {
  2663.     if (client_data == (XtPointer) u) {
  2664.         select_utype = u;
  2665.         select_loop = 0;
  2666.         return;
  2667.     }
  2668.     }
  2669.     select_utype = NONUTYPE;
  2670.     select_loop = 0;
  2671.     return;
  2672. }
  2673.  
  2674. int
  2675. dir_select_popup(side, x, y)
  2676. Side *side;
  2677. Position x;
  2678. Position y;
  2679. {
  2680.     Widget box, shell, command;
  2681.     int dir;
  2682.  
  2683.     select_dir = -1;
  2684.  
  2685.     shell =
  2686.       XtVaCreatePopupShell("dirSelect", transientShellWidgetClass,
  2687.                side->ui->shell,
  2688.                XtNx, x,
  2689.                XtNy, y,
  2690.                NULL);
  2691.     box = XtVaCreateManagedWidget("box", boxWidgetClass, shell,
  2692.                NULL);
  2693.  
  2694.     for_all_directions(dir) {
  2695.     command =
  2696.        XtVaCreateManagedWidget(dirnames[dir], commandWidgetClass, box,
  2697.                    NULL);
  2698.     XtAddCallback(command, XtNcallback, dir_select_call,
  2699.               (XtPointer) dir);
  2700.     }
  2701.  
  2702.     XtPopup(shell, XtGrabExclusive);
  2703.  
  2704.     XWarpPointer(side->ui->dpy, None, XtWindow(box), 0, 0, 0, 0, 32, 32);
  2705.  
  2706.     /* replacement for XtAppMainLoop(thisapp): */
  2707.     select_loop = 1;
  2708.     while (select_loop) {
  2709.     XEvent event;
  2710.  
  2711.     XtAppNextEvent(thisapp, &event);
  2712.     XtDispatchEvent(&event);
  2713.     }
  2714.     XtPopdown(shell);
  2715.     XtDestroyWidget(shell);
  2716.  
  2717.     return select_dir;
  2718. }
  2719.  
  2720. static void 
  2721. dir_select_call (w, client_data, call_data)
  2722. Widget w;
  2723. XtPointer client_data;
  2724. XtPointer call_data;
  2725. {
  2726.     int dir;
  2727.  
  2728.     for_all_directions(dir) {
  2729.     if (client_data == (XtPointer) dir) {
  2730.         select_dir = dir;
  2731.         select_loop = 0;
  2732.         return;
  2733.     }
  2734.     }
  2735.     select_dir = -1;
  2736.     select_loop = 0;
  2737.     return;
  2738. }
  2739.  
  2740. int
  2741. integer_select_popup(side, x, y, value, prompt)
  2742. Side *side;
  2743. Position x;
  2744. Position y;
  2745. int value;
  2746. char *prompt;
  2747. {
  2748.     int result;
  2749.     char *string;
  2750.  
  2751.     sprintf(tmpbuf, "%d", value);
  2752.     string_select_popup(side, x, y, buffer, tmpbuf, prompt);
  2753.     if (sscanf(string, "%d", &result) != 1)
  2754.       result = 0;
  2755.  
  2756.     return result;
  2757. }
  2758.  
  2759. void
  2760. string_select_popup(side, x, y, result, value, prompt)
  2761. Side *side;
  2762. Position x;
  2763. Position y;
  2764. char *result;
  2765. char *value;
  2766. char *prompt;
  2767. {
  2768.     Widget shell, dialog;
  2769.     char *string;
  2770.  
  2771.     select_task = -1;
  2772.  
  2773.     shell =
  2774.       XtVaCreatePopupShell("stringSelect", transientShellWidgetClass,
  2775.                side->ui->shell,
  2776.                XtNx, x,
  2777.                XtNy, y,
  2778.                NULL);
  2779.  
  2780.     dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, shell,
  2781.                       XtNlabel, prompt,
  2782.                       XtNvalue, value,
  2783.                       NULL);
  2784.  
  2785.     XtPopup(shell, XtGrabExclusive);
  2786.     XWarpPointer(side->ui->dpy, None, XtWindow(dialog), 0, 0, 0, 0, 32, 32);
  2787.  
  2788.     /* replacement for XtAppMainLoop(thisapp): */
  2789.     select_loop = 1;
  2790.     while (select_loop) {
  2791.     XEvent event;
  2792.  
  2793.     XtAppNextEvent(thisapp, &event);
  2794.     XtDispatchEvent(&event);
  2795.     }
  2796.  
  2797.     string = XawDialogGetValueString(dialog);
  2798.     /* safer to save the string, XtDestroyWidget may deallocate it */
  2799.     strcpy(result, string);
  2800.  
  2801.     XtPopdown(shell);
  2802.     XtDestroyWidget(shell);
  2803. }
  2804.  
  2805. static void 
  2806. handle_done_string_select (w, event, params, numparms)
  2807. Widget w;
  2808. XEvent *event;
  2809. String *params;
  2810. Cardinal *numparms;
  2811. {
  2812.     select_loop = 0;
  2813. }
  2814.  
  2815.  
  2816. static void 
  2817. order_tparms_call (w, client_data, call_data)
  2818. Widget w;
  2819. XtPointer client_data;
  2820. XtPointer call_data;
  2821. {
  2822.     Side *side;
  2823.     OrderInterface *ordi;
  2824.     Boolean state;
  2825.     Map *map;
  2826.     char *lab;
  2827.     int utype, uid, i;
  2828.     Unit *unit;
  2829.     Position x, y;
  2830.     Task *task;
  2831.  
  2832.     if (!find_side_and_ordi_via_widget(w, &side, &ordi))
  2833.       return;
  2834.     map = side->ui->maps;
  2835.  
  2836.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  2837.  
  2838.     XtVaGetValues(side->ui->orders_shell, XtNx, &x, XtNy, &y, NULL);
  2839.     x += 32;  y += 32;
  2840.  
  2841.     task = side->ui->sorder_task_edit;
  2842.  
  2843.     if (state) {
  2844.     /* edit */
  2845.  
  2846.     for (i = 0; i < MAXTASKARGS; ++i)
  2847.       side->ui->sorder_edit->task->args[i] = 0;
  2848.  
  2849.     switch (task->type) {
  2850.  
  2851.     case TASK_NONE:
  2852.     case TASK_DISBAND:
  2853.         break;
  2854.  
  2855.     case TASK_BUILD:
  2856.         utype = utype_select_popup(side, x, y);
  2857.         if (utype != NONUTYPE) {
  2858.         task->args[0] = utype;
  2859.         task->args[3] = 99;
  2860.         }
  2861.         break;
  2862.  
  2863.     case TASK_CAPTURE:
  2864.     case TASK_HIT_UNIT:
  2865.         set_unit_from_map (side, map,
  2866.                    "select target unit, then press space",
  2867.                    (void *) &uid);
  2868.         unit = find_unit(uid);
  2869.         task->args[0] = unit->x;
  2870.         task->args[1] = unit->y;
  2871.         if (task->type == TASK_HIT_UNIT) {
  2872.         task->args[2] = NONUTYPE;
  2873.         task->args[3] = -1;
  2874.         }
  2875.         break;
  2876.  
  2877.     case TASK_MOVE_DIR:
  2878.         task->args[0] = dir_select_popup (side, x, y);
  2879.         task->args[1] = integer_select_popup(side, x, y, 99,
  2880.                          "enter distance");
  2881.         break;
  2882.  
  2883.     case TASK_MOVE_TO:
  2884.         task->args[2] = integer_select_popup(side, x, y, 0,
  2885.                          "enter distance");
  2886.         set_cell_from_map (side, map,
  2887.                    "select destination cell, then press space",
  2888.                    (void *) &task->args[0],
  2889.                    (void *) &task->args[1],
  2890.                    sizeof(task->args[0]));
  2891.         break;
  2892.  
  2893.     case TASK_HIT_POSITION:
  2894.         set_cell_from_map (side, map,
  2895.                    "select target cell, then press space",
  2896.                    (void *) &task->args[0],
  2897.                    (void *) &task->args[1],
  2898.                    sizeof(task->args[0]));
  2899.         break;
  2900.  
  2901.     case TASK_OCCUPY:
  2902.     case TASK_PICKUP:
  2903.         set_unit_from_map (side, map,
  2904.                    "select target unit, then press space",
  2905.                    (void *) &uid);
  2906.         break;
  2907.  
  2908.     case TASK_SENTRY:
  2909.         task->args[0] = integer_select_popup(side, x, y, 99,
  2910.                          "enter turn #");
  2911.         break;
  2912.  
  2913.     case TASK_DO_ACTION:
  2914.     default:
  2915.         beep(side);
  2916.     }
  2917.     /* get task description, chop task name and separator */
  2918.     task_desc(buffer, task);
  2919.     lab = buffer + strlen(taskdefns[task->type].name);
  2920.     while (*lab == ' ' || *lab == ',')
  2921.       lab++;
  2922.     XtVaSetValues(side->ui->ordi_edit->tparms, XtNlabel, lab, NULL);
  2923.  
  2924.     } else {
  2925.     /* display */
  2926.     if (ordi->sorder->task->type == TASK_MOVE_TO) {
  2927.         if (in_area(ordi->sorder->a1, ordi->sorder->a2)) {
  2928.         map->curx = ordi->sorder->task->args[0];
  2929.         map->cury = ordi->sorder->task->args[1];
  2930.         map->curunit = NULL;
  2931.         recenter(side, map, ordi->sorder->task->args[0],
  2932.                         ordi->sorder->task->args[1]);
  2933.         do_x_flash(side, map);
  2934.         } else {
  2935.         beep(side);
  2936.         }
  2937.     }
  2938.     }
  2939. }
  2940.  
  2941. void 
  2942. set_cell_from_map (side, map, prompt, px, py, size)
  2943. Side *side;
  2944. Map *map;
  2945. char *prompt;
  2946. void *px, *py;
  2947. int size;
  2948. {
  2949.     save_cur(side, map);
  2950.     RaiseWidget(XtParent(map->mainwidget));
  2951.     map->curtool = looktool;
  2952.     set_tool_cursor(side, map);
  2953.     update_controls(side, map);
  2954.     side->ui->grok_p1 = px;
  2955.     side->ui->grok_p2 = py;
  2956.     side->ui->grok_size = size;
  2957.     ask_position(side, map, prompt, aux_set_cell);
  2958. }
  2959.  
  2960. static void
  2961. aux_set_cell(side, map, cancel)
  2962. Side *side;
  2963. Map *map;
  2964. int cancel;
  2965. {
  2966.     int x, y;
  2967.     Boolean state;
  2968.  
  2969.     if (cancel)
  2970.       return;
  2971.     if (grok_position(side, map, &x, &y)) {
  2972. /*    erase_current(side, map, x, y, NULL); */
  2973.  
  2974.     XtVaGetValues(side->ui->ordi_edit->toggle, XtNstate, &state, NULL);
  2975.     if (!state) {
  2976.         beep(side);
  2977.         return;
  2978.     }
  2979.     RaiseWidget(side->ui->orders_shell);
  2980.     switch (side->ui->grok_size) {
  2981.     case 1:
  2982.         *((char *)  side->ui->grok_p1) = x;
  2983.         *((char *)  side->ui->grok_p2) = y;
  2984.         break;
  2985.     case 2:
  2986.         *((short *) side->ui->grok_p1) = x;
  2987.         *((short *) side->ui->grok_p2) = y;
  2988.         break;
  2989.     case 4:
  2990.         *((int *)   side->ui->grok_p1) = x;
  2991.         *((int *)   side->ui->grok_p2) = y;
  2992.         break;
  2993.     default:
  2994.         beep(side);
  2995.         return;
  2996.     }
  2997.     update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
  2998.                  side->ui->sorder_types_edit,
  2999.                  side->ui->sorder_task_edit);
  3000.     } else {
  3001.     map->modalhandler = aux_set_cell;
  3002.     }
  3003. }
  3004.  
  3005. void 
  3006. set_unit_from_map (side, map, prompt, puid)
  3007. Side *side;
  3008. Map *map;
  3009. char *prompt;
  3010. int *puid;
  3011. {
  3012.     save_cur(side, map);
  3013.     RaiseWidget(XtParent(map->mainwidget));
  3014.     map->curtool = looktool;
  3015.     set_tool_cursor(side, map);
  3016.     update_controls(side, map);
  3017.     side->ui->grok_p1 = (void *) puid;
  3018.     ask_position(side, map, prompt, aux_set_unit);
  3019. }
  3020.  
  3021. static void
  3022. aux_set_unit(side, map, cancel)
  3023. Side *side;
  3024. Map *map;
  3025. int cancel;
  3026. {
  3027.     int x, y;
  3028.     Boolean state;
  3029.  
  3030.     if (cancel)
  3031.       return;
  3032.     if (grok_position(side, map, &x, &y)) {
  3033. /*    erase_current(side, map, x, y, NULL); */
  3034.  
  3035.     XtVaGetValues(side->ui->ordi_edit->toggle, XtNstate, &state, NULL);
  3036.     if (!state) {
  3037.         beep(side);
  3038.         return;
  3039.     }
  3040.     RaiseWidget(side->ui->orders_shell);
  3041.  
  3042.     if (map->curunit == NULL)
  3043.       return;
  3044.     *((int *) side->ui->grok_p1) = map->curunit->id;
  3045.  
  3046.     update_order_widgets(side, side->ui->ordi_edit, side->ui->sorder_edit,
  3047.                  side->ui->sorder_types_edit,
  3048.                  side->ui->sorder_task_edit);
  3049.     } else {
  3050.     map->modalhandler = aux_set_unit;
  3051.     }
  3052. }
  3053.  
  3054. int 
  3055. find_side_and_ordi_via_widget(w, sidep, ordip)
  3056. Widget w;
  3057. Side **sidep;
  3058. OrderInterface **ordip;
  3059. {
  3060.     OrderInterface *ordi;
  3061.     Widget form = XtParent(w);
  3062.  
  3063.     if (!find_side_via_widget(w, sidep))
  3064.       return 0;
  3065.  
  3066.     for (ordi = (*sidep)->ui->orderlist; ordi != NULL; ordi = ordi->next) {
  3067.     if (ordi->form == form) {
  3068.         *ordip = ordi;
  3069.         return 1;
  3070.     }
  3071.     }
  3072.  
  3073.     return 0;
  3074. }
  3075.  
  3076. OrderInterface *
  3077. active_ordi(side)
  3078. Side *side;
  3079. {
  3080.     OrderInterface *ordi;
  3081.     Boolean state;
  3082.  
  3083.     for (ordi = side->ui->orderlist; ordi != NULL; ordi = ordi->next) {
  3084.     XtVaGetValues(ordi->toggle, XtNstate, &state, NULL);
  3085.     if (state)  return ordi;
  3086.     }
  3087.     return NULL;
  3088. }
  3089.  
  3090. int
  3091. count_sorder(side)
  3092. Side *side;
  3093. {
  3094.     StandingOrder *sorder;
  3095.     int num;
  3096.  
  3097.     for (sorder = side->orders,  num = 0;
  3098.      sorder != NULL;
  3099.      sorder = sorder->next,  num++);
  3100.  
  3101.     return num;
  3102. }
  3103.  
  3104. int
  3105. num_tasks()
  3106. {
  3107.     int i;
  3108.  
  3109.     for (i = 0; taskdefns[i].name != NULL; i++) {}
  3110.     return i;
  3111. }
  3112.